From 16adaf1b80013bee8d68ea994d95769be95a8548 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Thu, 27 Dec 2007 16:45:22 +0000
Subject: [PATCH] Swap the order of testing for control characters and for
 column delimiter in CopyAttributeOutText(), so that control characters are
 converted to the C-style escape sequences even if they happen to be equal to
 the column delimiter (as is true by default for tab, for example).  Oversight
 in my previous patch to restore pre-8.3 behavior of COPY OUT escaping.  Per
 report from Tomas Szepe.

---
 src/backend/commands/copy.c | 36 +++++++++++++++++++++---------------
 1 file changed, 21 insertions(+), 15 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 55ecf0098d4..a1aefcaad84 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.290 2007/12/03 00:03:05 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.291 2007/12/27 16:45:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -3094,13 +3094,7 @@ CopyAttributeOutText(CopyState cstate, char *string)
 		start = ptr;
 		while ((c = *ptr) != '\0')
 		{
-			if (c == '\\' || c == delimc)
-			{
-				DUMPSOFAR();
-				CopySendChar(cstate, '\\');
-				start = ptr++;	/* we include char in next run */
-			}
-			else if ((unsigned char) c < (unsigned char) 0x20)
+			if ((unsigned char) c < (unsigned char) 0x20)
 			{
 				/*
 				 * \r and \n must be escaped, the others are traditional.
@@ -3130,6 +3124,9 @@ CopyAttributeOutText(CopyState cstate, char *string)
 						c = 'v';
 						break;
 					default:
+						/* If it's the delimiter, must backslash it */
+						if (c == delimc)
+							break;
 						/* All ASCII control chars are length 1 */
 						ptr++;
 						continue;		/* fall to end of loop */
@@ -3140,6 +3137,12 @@ CopyAttributeOutText(CopyState cstate, char *string)
 				CopySendChar(cstate, c);
 				start = ++ptr;			/* do not include char in next run */
 			}
+			else if (c == '\\' || c == delimc)
+			{
+				DUMPSOFAR();
+				CopySendChar(cstate, '\\');
+				start = ptr++;	/* we include char in next run */
+			}
 			else if (IS_HIGHBIT_SET(c))
 				ptr += pg_encoding_mblen(cstate->client_encoding, ptr);
 			else
@@ -3151,13 +3154,7 @@ CopyAttributeOutText(CopyState cstate, char *string)
 		start = ptr;
 		while ((c = *ptr) != '\0')
 		{
-			if (c == '\\' || c == delimc)
-			{
-				DUMPSOFAR();
-				CopySendChar(cstate, '\\');
-				start = ptr++;	/* we include char in next run */
-			}
-			else if ((unsigned char) c < (unsigned char) 0x20)
+			if ((unsigned char) c < (unsigned char) 0x20)
 			{
 				/*
 				 * \r and \n must be escaped, the others are traditional.
@@ -3187,6 +3184,9 @@ CopyAttributeOutText(CopyState cstate, char *string)
 						c = 'v';
 						break;
 					default:
+						/* If it's the delimiter, must backslash it */
+						if (c == delimc)
+							break;
 						/* All ASCII control chars are length 1 */
 						ptr++;
 						continue;		/* fall to end of loop */
@@ -3197,6 +3197,12 @@ CopyAttributeOutText(CopyState cstate, char *string)
 				CopySendChar(cstate, c);
 				start = ++ptr;			/* do not include char in next run */
 			}
+			else if (c == '\\' || c == delimc)
+			{
+				DUMPSOFAR();
+				CopySendChar(cstate, '\\');
+				start = ptr++;	/* we include char in next run */
+			}
 			else
 				ptr++;
 		}
-- 
GitLab