Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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)