Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c3b7d2d

Browse files
committed
Allow \r and \r\n termination for COPY files.
Output \r\n termination on Win32. Disallow literal carriage return as a data value, backslash-carriage-return and \r still allowed. Doc changes already committed.
1 parent 9c48cae commit c3b7d2d

File tree

1 file changed

+84
-11
lines changed

1 file changed

+84
-11
lines changed

src/backend/commands/copy.c

Lines changed: 84 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.193 2003/04/19 19:55:37 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.194 2003/04/19 20:36:03 momjian Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -50,6 +50,13 @@
5050
#define ISOCTAL(c) (((c) >= '0') && ((c) <= '7'))
5151
#define OCTVALUE(c) ((c) - '0')
5252

53+
/* Default line termination */
54+
#ifndef WIN32
55+
#define PGEOL "\n"
56+
#else
57+
#define PGEOL "\r\n"
58+
#endif
59+
5360
/*
5461
* Represents the different source/dest cases we need to worry about at
5562
* the bottom level
@@ -71,9 +78,21 @@ typedef enum CopyReadResult
7178
END_OF_FILE
7279
} CopyReadResult;
7380

81+
/*
82+
* Represents the end-of-line terminator of the input
83+
*/
84+
typedef enum EolType
85+
{
86+
EOL_UNKNOWN,
87+
EOL_NL,
88+
EOL_CR,
89+
EOL_CRNL
90+
} EolType;
91+
92+
7493
/* non-export function prototypes */
7594
static void CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
76-
char *delim, char *null_print);
95+
bool pipe, char *delim, char *null_print);
7796
static void CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
7897
char *delim, char *null_print);
7998
static Oid GetInputFunction(Oid type);
@@ -82,7 +101,8 @@ static char *CopyReadAttribute(const char *delim, CopyReadResult *result);
82101
static void CopyAttributeOut(char *string, char *delim);
83102
static List *CopyGetAttnums(Relation rel, List *attnamelist);
84103

85-
static const char BinarySignature[12] = "PGBCOPY\n\377\r\n\0";
104+
/* The trailing null is part of the signature */
105+
static const char BinarySignature[] = "PGBCOPY\n\377\r\n";
86106

87107
/*
88108
* Static communication variables ... pretty grotty, but COPY has
@@ -94,6 +114,7 @@ static CopyDest copy_dest;
94114
static FILE *copy_file; /* if copy_dest == COPY_FILE */
95115
static StringInfo copy_msgbuf; /* if copy_dest == COPY_NEW_FE */
96116
static bool fe_eof; /* true if detected end of copy data */
117+
static EolType eol_type;
97118

98119
/*
99120
* These static variables are used to avoid incurring overhead for each
@@ -181,7 +202,10 @@ static void
181202
SendCopyEnd(bool binary, bool pipe)
182203
{
183204
if (!binary)
184-
CopySendData("\\.\n", 3);
205+
{
206+
CopySendString("\\.");
207+
CopySendString(!pipe ? PGEOL : "\n");
208+
}
185209
pq_endcopyout(false);
186210
}
187211

@@ -674,7 +698,7 @@ DoCopy(const CopyStmt *stmt)
674698
elog(ERROR, "COPY: %s is a directory", filename);
675699
}
676700
}
677-
CopyTo(rel, attnumlist, binary, oids, delim, null_print);
701+
CopyTo(rel, attnumlist, binary, oids, pipe, delim, null_print);
678702
}
679703

680704
if (!pipe)
@@ -697,7 +721,7 @@ DoCopy(const CopyStmt *stmt)
697721
* Copy from relation TO file.
698722
*/
699723
static void
700-
CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
724+
CopyTo(Relation rel, List *attnumlist, bool binary, bool oids, bool pipe,
701725
char *delim, char *null_print)
702726
{
703727
HeapTuple tuple;
@@ -762,7 +786,7 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
762786
int32 tmp;
763787

764788
/* Signature */
765-
CopySendData((char *) BinarySignature, 12);
789+
CopySendData((char *) BinarySignature, sizeof(BinarySignature));
766790
/* Integer layout field */
767791
tmp = 0x01020304;
768792
CopySendData(&tmp, sizeof(int32));
@@ -895,7 +919,7 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
895919
}
896920

897921
if (!binary)
898-
CopySendChar('\n');
922+
CopySendString(!pipe ? PGEOL : "\n");
899923

900924
MemoryContextSwitchTo(oldcontext);
901925
}
@@ -1076,7 +1100,8 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
10761100

10771101
/* Signature */
10781102
CopyGetData(readSig, 12);
1079-
if (CopyGetEof() || memcmp(readSig, BinarySignature, 12) != 0)
1103+
if (CopyGetEof() || memcmp(readSig, BinarySignature,
1104+
sizeof(BinarySignature)) != 0)
10801105
elog(ERROR, "COPY BINARY: file signature not recognized");
10811106
/* Integer layout field */
10821107
CopyGetData(&tmp, sizeof(int32));
@@ -1108,6 +1133,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
11081133

11091134
/* Initialize static variables */
11101135
copy_lineno = 0;
1136+
eol_type = EOL_UNKNOWN;
11111137
fe_eof = false;
11121138

11131139
/* Make room for a PARAM_EXEC value for domain constraint checks */
@@ -1520,8 +1546,44 @@ CopyReadAttribute(const char *delim, CopyReadResult *result)
15201546
*result = END_OF_FILE;
15211547
goto copy_eof;
15221548
}
1549+
if (c == '\r')
1550+
{
1551+
if (eol_type == EOL_NL)
1552+
elog(ERROR, "CopyReadAttribute: Literal carriage return data value\n"
1553+
"found in input that has newline termination; use \\r");
1554+
1555+
/* Check for \r\n on first line, _and_ handle \r\n. */
1556+
if (copy_lineno == 1 || eol_type == EOL_CRNL)
1557+
{
1558+
int c2 = CopyPeekChar();
1559+
if (c2 == '\n')
1560+
{
1561+
CopyDonePeek(c2, true); /* eat newline */
1562+
eol_type = EOL_CRNL;
1563+
}
1564+
else
1565+
{
1566+
/* found \r, but no \n */
1567+
if (eol_type == EOL_CRNL)
1568+
elog(ERROR, "CopyReadAttribute: Literal carriage return data value\n"
1569+
"found in input that has carriage return/newline termination; use \\r");
1570+
/* if we got here, it is the first line and we didn't get \n, so put it back */
1571+
CopyDonePeek(c2, false);
1572+
eol_type = EOL_CR;
1573+
}
1574+
}
1575+
*result = END_OF_LINE;
1576+
break;
1577+
}
15231578
if (c == '\n')
15241579
{
1580+
if (eol_type == EOL_CRNL)
1581+
elog(ERROR, "CopyReadAttribute: Literal newline data value found in input\n"
1582+
"that has carriage return/newline termination; use \\n");
1583+
if (eol_type == EOL_CR)
1584+
elog(ERROR, "CopyReadAttribute: Literal newline data value found in input\n"
1585+
"that has carriage return termination; use \\n");
1586+
eol_type = EOL_NL;
15251587
*result = END_OF_LINE;
15261588
break;
15271589
}
@@ -1611,9 +1673,20 @@ CopyReadAttribute(const char *delim, CopyReadResult *result)
16111673
c = '\v';
16121674
break;
16131675
case '.':
1676+
if (eol_type == EOL_CRNL)
1677+
{
1678+
c = CopyGetChar();
1679+
if (c == '\n')
1680+
elog(ERROR, "CopyReadAttribute: end-of-copy termination does not match previous input");
1681+
if (c != '\r')
1682+
elog(ERROR, "CopyReadAttribute: end-of-copy marker corrupt");
1683+
}
16141684
c = CopyGetChar();
1615-
if (c != '\n')
1616-
elog(ERROR, "CopyReadAttribute: end of record marker corrupted");
1685+
if (c != '\r' && c != '\n')
1686+
elog(ERROR, "CopyReadAttribute: end-of-copy marker corrupt");
1687+
if (((eol_type == EOL_NL || eol_type == EOL_CRNL) && c != '\n') ||
1688+
(eol_type == EOL_CR && c != '\r'))
1689+
elog(ERROR, "CopyReadAttribute: end-of-copy termination does not match previous input");
16171690
/*
16181691
* In protocol version 3, we should ignore anything after
16191692
* \. up to the protocol end of copy data. (XXX maybe

0 commit comments

Comments
 (0)