8
8
*
9
9
*
10
10
* 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 $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
50
50
#define ISOCTAL (c ) (((c) >= '0') && ((c) <= '7'))
51
51
#define OCTVALUE (c ) ((c) - '0')
52
52
53
+ /* Default line termination */
54
+ #ifndef WIN32
55
+ #define PGEOL "\n"
56
+ #else
57
+ #define PGEOL "\r\n"
58
+ #endif
59
+
53
60
/*
54
61
* Represents the different source/dest cases we need to worry about at
55
62
* the bottom level
@@ -71,9 +78,21 @@ typedef enum CopyReadResult
71
78
END_OF_FILE
72
79
} CopyReadResult ;
73
80
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
+
74
93
/* non-export function prototypes */
75
94
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 );
77
96
static void CopyFrom (Relation rel , List * attnumlist , bool binary , bool oids ,
78
97
char * delim , char * null_print );
79
98
static Oid GetInputFunction (Oid type );
@@ -82,7 +101,8 @@ static char *CopyReadAttribute(const char *delim, CopyReadResult *result);
82
101
static void CopyAttributeOut (char * string , char * delim );
83
102
static List * CopyGetAttnums (Relation rel , List * attnamelist );
84
103
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" ;
86
106
87
107
/*
88
108
* Static communication variables ... pretty grotty, but COPY has
@@ -94,6 +114,7 @@ static CopyDest copy_dest;
94
114
static FILE * copy_file ; /* if copy_dest == COPY_FILE */
95
115
static StringInfo copy_msgbuf ; /* if copy_dest == COPY_NEW_FE */
96
116
static bool fe_eof ; /* true if detected end of copy data */
117
+ static EolType eol_type ;
97
118
98
119
/*
99
120
* These static variables are used to avoid incurring overhead for each
@@ -181,7 +202,10 @@ static void
181
202
SendCopyEnd (bool binary , bool pipe )
182
203
{
183
204
if (!binary )
184
- CopySendData ("\\.\n" , 3 );
205
+ {
206
+ CopySendString ("\\." );
207
+ CopySendString (!pipe ? PGEOL : "\n" );
208
+ }
185
209
pq_endcopyout (false);
186
210
}
187
211
@@ -674,7 +698,7 @@ DoCopy(const CopyStmt *stmt)
674
698
elog (ERROR , "COPY: %s is a directory" , filename );
675
699
}
676
700
}
677
- CopyTo (rel , attnumlist , binary , oids , delim , null_print );
701
+ CopyTo (rel , attnumlist , binary , oids , pipe , delim , null_print );
678
702
}
679
703
680
704
if (!pipe )
@@ -697,7 +721,7 @@ DoCopy(const CopyStmt *stmt)
697
721
* Copy from relation TO file.
698
722
*/
699
723
static void
700
- CopyTo (Relation rel , List * attnumlist , bool binary , bool oids ,
724
+ CopyTo (Relation rel , List * attnumlist , bool binary , bool oids , bool pipe ,
701
725
char * delim , char * null_print )
702
726
{
703
727
HeapTuple tuple ;
@@ -762,7 +786,7 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
762
786
int32 tmp ;
763
787
764
788
/* Signature */
765
- CopySendData ((char * ) BinarySignature , 12 );
789
+ CopySendData ((char * ) BinarySignature , sizeof ( BinarySignature ) );
766
790
/* Integer layout field */
767
791
tmp = 0x01020304 ;
768
792
CopySendData (& tmp , sizeof (int32 ));
@@ -895,7 +919,7 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
895
919
}
896
920
897
921
if (!binary )
898
- CopySendChar ( '\n' );
922
+ CopySendString (! pipe ? PGEOL : "\n" );
899
923
900
924
MemoryContextSwitchTo (oldcontext );
901
925
}
@@ -1076,7 +1100,8 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
1076
1100
1077
1101
/* Signature */
1078
1102
CopyGetData (readSig , 12 );
1079
- if (CopyGetEof () || memcmp (readSig , BinarySignature , 12 ) != 0 )
1103
+ if (CopyGetEof () || memcmp (readSig , BinarySignature ,
1104
+ sizeof (BinarySignature )) != 0 )
1080
1105
elog (ERROR , "COPY BINARY: file signature not recognized" );
1081
1106
/* Integer layout field */
1082
1107
CopyGetData (& tmp , sizeof (int32 ));
@@ -1108,6 +1133,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
1108
1133
1109
1134
/* Initialize static variables */
1110
1135
copy_lineno = 0 ;
1136
+ eol_type = EOL_UNKNOWN ;
1111
1137
fe_eof = false;
1112
1138
1113
1139
/* Make room for a PARAM_EXEC value for domain constraint checks */
@@ -1520,8 +1546,44 @@ CopyReadAttribute(const char *delim, CopyReadResult *result)
1520
1546
* result = END_OF_FILE ;
1521
1547
goto copy_eof ;
1522
1548
}
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
+ }
1523
1578
if (c == '\n' )
1524
1579
{
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 ;
1525
1587
* result = END_OF_LINE ;
1526
1588
break ;
1527
1589
}
@@ -1611,9 +1673,20 @@ CopyReadAttribute(const char *delim, CopyReadResult *result)
1611
1673
c = '\v' ;
1612
1674
break ;
1613
1675
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
+ }
1614
1684
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" );
1617
1690
/*
1618
1691
* In protocol version 3, we should ignore anything after
1619
1692
* \. up to the protocol end of copy data. (XXX maybe
0 commit comments