88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.265 2006/05/25 18:42:17 tgl Exp $
11+ * $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.266 2006/05/26 22:50:02 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
@@ -95,7 +95,8 @@ typedef struct CopyStateData
9595/* low-level state data */
9696CopyDest copy_dest ;/* type of copy source/destination */
9797FILE * copy_file ;/* used if copy_dest == COPY_FILE */
98- StringInfo fe_msgbuf ;/* used if copy_dest == COPY_NEW_FE */
98+ StringInfo fe_msgbuf ;/* used for all dests during COPY TO, only
99+ * for dest == COPY_NEW_FE in COPY FROM */
99100bool fe_copy ;/* true for all FE copy dests */
100101bool fe_eof ;/* true if detected end of copy data */
101102EolType eol_type ;/* EOL type of input */
@@ -287,7 +288,6 @@ SendCopyBegin(CopyState cstate)
287288pq_sendint (& buf ,format ,2 );/* per-column formats */
288289pq_endmessage (& buf );
289290cstate -> copy_dest = COPY_NEW_FE ;
290- cstate -> fe_msgbuf = makeStringInfo ();
291291}
292292else if (PG_PROTOCOL_MAJOR (FrontendProtocol ) >=2 )
293293{
@@ -364,23 +364,16 @@ SendCopyEnd(CopyState cstate)
364364{
365365if (cstate -> copy_dest == COPY_NEW_FE )
366366{
367- if (cstate -> binary )
368- {
369- /* Need to flush out file trailer word */
370- CopySendEndOfRow (cstate );
371- }
372- else
373- {
374- /* Shouldn't have any unsent data */
375- Assert (cstate -> fe_msgbuf -> len == 0 );
376- }
367+ /* Shouldn't have any unsent data */
368+ Assert (cstate -> fe_msgbuf -> len == 0 );
377369/* Send Copy Done message */
378370pq_putemptymessage ('c' );
379371}
380372else
381373{
382- /* The FE/BE protocol uses \n as newline for all platforms */
383- CopySendData (cstate ,"\\.\n" ,3 );
374+ CopySendData (cstate ,"\\." ,2 );
375+ /* Need to flush out the trailer (this also appends a newline) */
376+ CopySendEndOfRow (cstate );
384377pq_endcopyout (false);
385378}
386379}
@@ -390,53 +383,34 @@ SendCopyEnd(CopyState cstate)
390383 * CopySendString does the same for null-terminated strings
391384 * CopySendChar does the same for single characters
392385 * CopySendEndOfRow does the appropriate thing at end of each data row
386+ *(data is not actually flushed except by CopySendEndOfRow)
393387 *
394388 * NB: no data conversion is applied by these functions
395389 *----------
396390 */
397391static void
398392CopySendData (CopyState cstate ,void * databuf ,int datasize )
399393{
400- switch (cstate -> copy_dest )
401- {
402- case COPY_FILE :
403- fwrite (databuf ,datasize ,1 ,cstate -> copy_file );
404- if (ferror (cstate -> copy_file ))
405- ereport (ERROR ,
406- (errcode_for_file_access (),
407- errmsg ("could not write to COPY file: %m" )));
408- break ;
409- case COPY_OLD_FE :
410- if (pq_putbytes ((char * )databuf ,datasize ))
411- {
412- /* no hope of recovering connection sync, so FATAL */
413- ereport (FATAL ,
414- (errcode (ERRCODE_CONNECTION_FAILURE ),
415- errmsg ("connection lost during COPY to stdout" )));
416- }
417- break ;
418- case COPY_NEW_FE :
419- appendBinaryStringInfo (cstate -> fe_msgbuf ,
420- (char * )databuf ,datasize );
421- break ;
422- }
394+ appendBinaryStringInfo (cstate -> fe_msgbuf , (char * )databuf ,datasize );
423395}
424396
425397static void
426398CopySendString (CopyState cstate ,const char * str )
427399{
428- CopySendData (cstate , ( void * ) str ,strlen (str ));
400+ appendBinaryStringInfo (cstate -> fe_msgbuf , str ,strlen (str ));
429401}
430402
431403static void
432404CopySendChar (CopyState cstate ,char c )
433405{
434- CopySendData (cstate , & c , 1 );
406+ appendStringInfoCharMacro (cstate -> fe_msgbuf , c );
435407}
436408
437409static void
438410CopySendEndOfRow (CopyState cstate )
439411{
412+ StringInfo fe_msgbuf = cstate -> fe_msgbuf ;
413+
440414switch (cstate -> copy_dest )
441415{
442416case COPY_FILE :
@@ -449,24 +423,40 @@ CopySendEndOfRow(CopyState cstate)
449423CopySendString (cstate ,"\r\n" );
450424#endif
451425}
426+
427+ (void )fwrite (fe_msgbuf -> data ,fe_msgbuf -> len ,
428+ 1 ,cstate -> copy_file );
429+ if (ferror (cstate -> copy_file ))
430+ ereport (ERROR ,
431+ (errcode_for_file_access (),
432+ errmsg ("could not write to COPY file: %m" )));
452433break ;
453434case COPY_OLD_FE :
454435/* The FE/BE protocol uses \n as newline for all platforms */
455436if (!cstate -> binary )
456437CopySendChar (cstate ,'\n' );
438+
439+ if (pq_putbytes (fe_msgbuf -> data ,fe_msgbuf -> len ))
440+ {
441+ /* no hope of recovering connection sync, so FATAL */
442+ ereport (FATAL ,
443+ (errcode (ERRCODE_CONNECTION_FAILURE ),
444+ errmsg ("connection lost during COPY to stdout" )));
445+ }
457446break ;
458447case COPY_NEW_FE :
459448/* The FE/BE protocol uses \n as newline for all platforms */
460449if (!cstate -> binary )
461450CopySendChar (cstate ,'\n' );
451+
462452/* Dump the accumulated row as one CopyData message */
463- (void )pq_putmessage ('d' ,cstate -> fe_msgbuf -> data ,
464- cstate -> fe_msgbuf -> len );
465- /* Reset fe_msgbuf to empty */
466- cstate -> fe_msgbuf -> len = 0 ;
467- cstate -> fe_msgbuf -> data [0 ]= '\0' ;
453+ (void )pq_putmessage ('d' ,fe_msgbuf -> data ,fe_msgbuf -> len );
468454break ;
469455}
456+
457+ /* Reset fe_msgbuf to empty */
458+ fe_msgbuf -> len = 0 ;
459+ fe_msgbuf -> data [0 ]= '\0' ;
470460}
471461
472462/*
@@ -1237,6 +1227,9 @@ CopyTo(CopyState cstate)
12371227attr_count = list_length (cstate -> attnumlist );
12381228null_print_client = cstate -> null_print ;/* default */
12391229
1230+ /* We use fe_msgbuf as a per-row buffer regardless of copy_dest */
1231+ cstate -> fe_msgbuf = makeStringInfo ();
1232+
12401233/* Get info about the columns we need to process. */
12411234out_functions = (FmgrInfo * )palloc (num_phys_attrs * sizeof (FmgrInfo ));
12421235force_quote = (bool * )palloc (num_phys_attrs * sizeof (bool ));
@@ -1423,6 +1416,8 @@ CopyTo(CopyState cstate)
14231416{
14241417/* Generate trailer for a binary copy */
14251418CopySendInt16 (cstate ,-1 );
1419+ /* Need to flush out the trailer */
1420+ CopySendEndOfRow (cstate );
14261421}
14271422
14281423MemoryContextDelete (mycontext );