33 *
44 * Copyright (c) 2000-2006, PostgreSQL Global Development Group
55 *
6- * $PostgreSQL: pgsql/src/bin/psql/copy.c,v 1.60 2006/03/05 15:58:51 momjian Exp $
6+ * $PostgreSQL: pgsql/src/bin/psql/copy.c,v 1.61 2006/05/26 19:51:29 tgl Exp $
77 */
88#include "postgres_fe.h"
99#include "copy.h"
1010
11- #include <errno.h>
1211#include <signal.h>
1312#include <sys/stat.h>
1413#ifndef WIN32
3736 *
3837 * The documented preferred syntax is:
3938 *\copy tablename [(columnlist)] from|to filename
40- *[ with ] [ oids ] [ delimiter [as] char ] [ null [as] string ]
41- * (binary is not here yet)
39+ * [ with ] [ binary ] [ oids ] [ delimiter [as] char ] [ null [as] string ]
4240 *
4341 * The pre-7.3 syntax was:
44- *\copy tablename [(columnlist)] [with oids] from|to filename
42+ *\copy[ binary ] tablename [(columnlist)] [with oids] from|to filename
4543 *[ [using] delimiters char ] [ with null as string ]
4644 *
4745 * The actual accepted syntax is a rather unholy combination of these,
@@ -131,8 +129,6 @@ parse_slash_copy(const char *args)
131129if (!token )
132130gotoerror ;
133131
134- #ifdef NOT_USED
135- /* this is not implemented yet */
136132if (pg_strcasecmp (token ,"binary" )== 0 )
137133{
138134result -> binary = true;
@@ -141,7 +137,6 @@ parse_slash_copy(const char *args)
141137if (!token )
142138gotoerror ;
143139}
144- #endif
145140
146141result -> table = pg_strdup (token );
147142
@@ -284,9 +279,10 @@ parse_slash_copy(const char *args)
284279
285280fetch_next = true;
286281
287- /* someday allow BINARY here */
288282if (pg_strcasecmp (token ,"oids" )== 0 )
289283result -> oids = true;
284+ else if (pg_strcasecmp (token ,"binary" )== 0 )
285+ result -> binary = true;
290286else if (pg_strcasecmp (token ,"csv" )== 0 )
291287result -> csv_mode = true;
292288else if (pg_strcasecmp (token ,"header" )== 0 )
@@ -442,6 +438,8 @@ do_copy(const char *args)
442438initPQExpBuffer (& query );
443439
444440printfPQExpBuffer (& query ,"COPY " );
441+
442+ /* Uses old COPY syntax for backward compatibility 2002-06-19 */
445443if (options -> binary )
446444appendPQExpBuffer (& query ,"BINARY " );
447445
@@ -523,7 +521,8 @@ do_copy(const char *args)
523521else
524522{
525523if (options -> file )
526- copystream = fopen (options -> file ,"w" );
524+ copystream = fopen (options -> file ,
525+ options -> binary ?PG_BINARY_W :"w" );
527526else if (!options -> psql_inout )
528527copystream = pset .queryFout ;
529528else
@@ -558,7 +557,8 @@ do_copy(const char *args)
558557success = handleCopyOut (pset .db ,copystream );
559558break ;
560559case PGRES_COPY_IN :
561- success = handleCopyIn (pset .db ,copystream );
560+ success = handleCopyIn (pset .db ,copystream ,
561+ PQbinaryTuples (result ));
562562break ;
563563case PGRES_NONFATAL_ERROR :
564564case PGRES_FATAL_ERROR :
@@ -622,12 +622,23 @@ handleCopyOut(PGconn *conn, FILE *copystream)
622622
623623if (buf )
624624{
625- fputs (buf ,copystream );
625+ if (fwrite (buf ,1 ,ret ,copystream )!= ret )
626+ {
627+ if (OK )/* complain only once, keep reading data */
628+ psql_error ("could not write COPY data: %s\n" ,
629+ strerror (errno ));
630+ OK = false;
631+ }
626632PQfreemem (buf );
627633}
628634}
629635
630- fflush (copystream );
636+ if (OK && fflush (copystream ))
637+ {
638+ psql_error ("could not write COPY data: %s\n" ,
639+ strerror (errno ));
640+ OK = false;
641+ }
631642
632643if (ret == -2 )
633644{
@@ -657,6 +668,7 @@ handleCopyOut(PGconn *conn, FILE *copystream)
657668 * conn should be a database connection that you just issued COPY FROM on
658669 * and got back a PGRES_COPY_IN result.
659670 * copystream is the file stream to read the data from.
671+ * isbinary can be set from PQbinaryTuples().
660672 *
661673 * result is true if successful, false if not.
662674 */
@@ -665,13 +677,10 @@ handleCopyOut(PGconn *conn, FILE *copystream)
665677#define COPYBUFSIZ 8192
666678
667679bool
668- handleCopyIn (PGconn * conn ,FILE * copystream )
680+ handleCopyIn (PGconn * conn ,FILE * copystream , bool isbinary )
669681{
670682bool OK = true;
671683const char * prompt ;
672- bool copydone = false;
673- bool firstload ;
674- bool linedone ;
675684char buf [COPYBUFSIZ ];
676685PGresult * res ;
677686
@@ -686,59 +695,89 @@ handleCopyIn(PGconn *conn, FILE *copystream)
686695else
687696prompt = NULL ;
688697
689- while (!copydone )
690- {/* for each input line ... */
698+ if (isbinary )
699+ {
700+ int buflen ;
701+
702+ /* interactive input probably silly, but give one prompt anyway */
691703if (prompt )
692704{
693705fputs (prompt ,stdout );
694706fflush (stdout );
695707}
696-
697- firstload = true;
698- linedone = false;
699708
700- while (!linedone )
701- {/* for each bufferload in line ... */
702- int linelen ;
703-
704- if (!fgets (buf ,COPYBUFSIZ ,copystream ))
709+ while ((buflen = fread (buf ,1 ,COPYBUFSIZ ,copystream ))> 0 )
710+ {
711+ if (PQputCopyData (conn ,buf ,buflen ) <=0 )
705712{
706- if (ferror (copystream ))
707- OK = false;
708- copydone = true;
713+ OK = false;
709714break ;
710715}
716+ }
717+ }
718+ else
719+ {
720+ bool copydone = false;
711721
712- linelen = strlen (buf );
713-
714- /* current line is done? */
715- if (linelen > 0 && buf [linelen - 1 ]== '\n' )
716- linedone = true;
722+ while (!copydone )
723+ {/* for each input line ... */
724+ bool firstload ;
725+ bool linedone ;
717726
718- /* check for EOF marker, but not on a partial line */
719- if (firstload )
727+ if (prompt )
720728{
721- if (strcmp (buf ,"\\.\n" )== 0 ||
722- strcmp (buf ,"\\.\r\n" )== 0 )
729+ fputs (prompt ,stdout );
730+ fflush (stdout );
731+ }
732+
733+ firstload = true;
734+ linedone = false;
735+
736+ while (!linedone )
737+ {/* for each bufferload in line ... */
738+ int linelen ;
739+
740+ if (!fgets (buf ,COPYBUFSIZ ,copystream ))
723741{
724742copydone = true;
725743break ;
726744}
745+
746+ linelen = strlen (buf );
747+
748+ /* current line is done? */
749+ if (linelen > 0 && buf [linelen - 1 ]== '\n' )
750+ linedone = true;
751+
752+ /* check for EOF marker, but not on a partial line */
753+ if (firstload )
754+ {
755+ if (strcmp (buf ,"\\.\n" )== 0 ||
756+ strcmp (buf ,"\\.\r\n" )== 0 )
757+ {
758+ copydone = true;
759+ break ;
760+ }
727761
728- firstload = false;
729- }
762+ firstload = false;
763+ }
730764
731- if (PQputCopyData (conn ,buf ,linelen ) <=0 )
732- {
733- OK = false;
734- copydone = true;
735- break ;
765+ if (PQputCopyData (conn ,buf ,linelen ) <=0 )
766+ {
767+ OK = false;
768+ copydone = true;
769+ break ;
770+ }
736771}
737- }
738772
739- pset .lineno ++ ;
773+ pset .lineno ++ ;
774+ }
740775}
741776
777+ /* Check for read error */
778+ if (ferror (copystream ))
779+ OK = false;
780+
742781/* Terminate data transfer */
743782if (PQputCopyEnd (conn ,
744783OK ?NULL :_ ("aborted due to read failure" )) <=0 )