88 *
99 *
1010 * IDENTIFICATION
11- * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.193 2003/04/1919:55:37 momjian Exp $
11+ * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.194 2003/04/1920:36:03 momjian Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
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
7178END_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 */
7594static void CopyTo (Relation rel ,List * attnumlist ,bool binary ,bool oids ,
76- char * delim ,char * null_print );
95+ bool pipe , char * delim ,char * null_print );
7796static void CopyFrom (Relation rel ,List * attnumlist ,bool binary ,bool oids ,
7897char * delim ,char * null_print );
7998static Oid GetInputFunction (Oid type );
@@ -82,7 +101,8 @@ static char *CopyReadAttribute(const char *delim, CopyReadResult *result);
82101static void CopyAttributeOut (char * string ,char * delim );
83102static 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;
94114static FILE * copy_file ;/* if copy_dest == COPY_FILE */
95115static StringInfo copy_msgbuf ;/* if copy_dest == COPY_NEW_FE */
96116static 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
181202SendCopyEnd (bool binary ,bool pipe )
182203{
183204if (!binary )
184- CopySendData ("\\.\n" ,3 );
205+ {
206+ CopySendString ("\\." );
207+ CopySendString (!pipe ?PGEOL :"\n" );
208+ }
185209pq_endcopyout (false);
186210}
187211
@@ -674,7 +698,7 @@ DoCopy(const CopyStmt *stmt)
674698elog (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
680704if (!pipe )
@@ -697,7 +721,7 @@ DoCopy(const CopyStmt *stmt)
697721 * Copy from relation TO file.
698722 */
699723static void
700- CopyTo (Relation rel ,List * attnumlist ,bool binary ,bool oids ,
724+ CopyTo (Relation rel ,List * attnumlist ,bool binary ,bool oids ,bool pipe ,
701725char * delim ,char * null_print )
702726{
703727HeapTuple tuple ;
@@ -762,7 +786,7 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
762786int32 tmp ;
763787
764788/* Signature */
765- CopySendData ((char * )BinarySignature ,12 );
789+ CopySendData ((char * )BinarySignature ,sizeof ( BinarySignature ) );
766790/* Integer layout field */
767791tmp = 0x01020304 ;
768792CopySendData (& tmp ,sizeof (int32 ));
@@ -895,7 +919,7 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
895919}
896920
897921if (!binary )
898- CopySendChar ( '\n' );
922+ CopySendString (! pipe ? PGEOL : "\n" );
899923
900924MemoryContextSwitchTo (oldcontext );
901925}
@@ -1076,7 +1100,8 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
10761100
10771101/* Signature */
10781102CopyGetData (readSig ,12 );
1079- if (CopyGetEof ()|| memcmp (readSig ,BinarySignature ,12 )!= 0 )
1103+ if (CopyGetEof ()|| memcmp (readSig ,BinarySignature ,
1104+ sizeof (BinarySignature ))!= 0 )
10801105elog (ERROR ,"COPY BINARY: file signature not recognized" );
10811106/* Integer layout field */
10821107CopyGetData (& tmp ,sizeof (int32 ));
@@ -1108,6 +1133,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
11081133
11091134/* Initialize static variables */
11101135copy_lineno = 0 ;
1136+ eol_type = EOL_UNKNOWN ;
11111137fe_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 ;
15211547gotocopy_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+ }
15231578if (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 ;
15261588break ;
15271589}
@@ -1611,9 +1673,20 @@ CopyReadAttribute(const char *delim, CopyReadResult *result)
16111673c = '\v' ;
16121674break ;
16131675case '.' :
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+ }
16141684c = 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