@@ -187,15 +187,15 @@ typedef struct CopyStateData
187187TransitionCaptureState * transition_capture ;
188188
189189/*
190- * These variables are used to reduce overhead intextual COPY FROM.
190+ * These variables are used to reduce overhead in COPY FROM.
191191 *
192192 * attribute_buf holds the separated, de-escaped text for each field of
193193 * the current line. The CopyReadAttributes functions return arrays of
194194 * pointers into this buffer. We avoid palloc/pfree overhead by re-using
195195 * the buffer on each cycle.
196196 *
197- *( In binary COPY FROM, attribute_buf holds the binary data for the
198- * current field,while theother variables are not used.)
197+ * In binary COPY FROM, attribute_buf holds the binary data for the
198+ * current field,but theusage is otherwise similar.
199199 */
200200StringInfoData attribute_buf ;
201201
@@ -209,23 +209,27 @@ typedef struct CopyStateData
209209 * input cycle is first to read the whole line into line_buf, convert it
210210 * to server encoding there, and then extract the individual attribute
211211 * fields into attribute_buf. line_buf is preserved unmodified so that we
212- * can display it in error messages if appropriate.
212+ * can display it in error messages if appropriate. (In binary mode,
213+ * line_buf is not used.)
213214 */
214215StringInfoData line_buf ;
215216bool line_buf_converted ;/* converted to server encoding? */
216217bool line_buf_valid ;/* contains the row being processed? */
217218
218219/*
219220 * Finally, raw_buf holds raw data read from the data source (file or
220- * client connection). CopyReadLine parses this data sufficiently to
221- * locate line boundaries, then transfers the data to line_buf and
222- * converts it. Note: we guarantee that there is a \0 at
223- * raw_buf[raw_buf_len].
221+ * client connection). In text mode, CopyReadLine parses this data
222+ * sufficiently to locate line boundaries, then transfers the data to
223+ * line_buf and converts it. In binary mode, CopyReadBinaryData fetches
224+ * appropriate amounts of data from this buffer. In both modes, we
225+ * guarantee that there is a \0 at raw_buf[raw_buf_len].
224226 */
225227#define RAW_BUF_SIZE 65536/* we palloc RAW_BUF_SIZE+1 bytes */
226228char * raw_buf ;
227229int raw_buf_index ;/* next byte to process */
228230int raw_buf_len ;/* total # of bytes stored */
231+ /* Shorthand for number of unconsumed bytes available in raw_buf */
232+ #define RAW_BUF_BYTES (cstate ) ((cstate)->raw_buf_len - (cstate)->raw_buf_index)
229233}CopyStateData ;
230234
231235/* DestReceiver for COPY (query) TO */
@@ -394,6 +398,8 @@ static void CopySendInt32(CopyState cstate, int32 val);
394398static bool CopyGetInt32 (CopyState cstate ,int32 * val );
395399static void CopySendInt16 (CopyState cstate ,int16 val );
396400static bool CopyGetInt16 (CopyState cstate ,int16 * val );
401+ static bool CopyLoadRawBuf (CopyState cstate );
402+ static int CopyReadBinaryData (CopyState cstate ,char * dest ,int nbytes );
397403
398404
399405/*
@@ -723,7 +729,7 @@ CopyGetData(CopyState cstate, void *databuf, int minread, int maxread)
723729/*
724730 * CopySendInt32 sends an int32 in network byte order
725731 */
726- static void
732+ static inline void
727733CopySendInt32 (CopyState cstate ,int32 val )
728734{
729735uint32 buf ;
@@ -737,12 +743,12 @@ CopySendInt32(CopyState cstate, int32 val)
737743 *
738744 * Returns true if OK, false if EOF
739745 */
740- static bool
746+ static inline bool
741747CopyGetInt32 (CopyState cstate ,int32 * val )
742748{
743749uint32 buf ;
744750
745- if (CopyGetData (cstate ,& buf , sizeof ( buf ) ,sizeof (buf ))!= sizeof (buf ))
751+ if (CopyReadBinaryData (cstate ,( char * ) & buf ,sizeof (buf ))!= sizeof (buf ))
746752{
747753* val = 0 ;/* suppress compiler warning */
748754return false;
@@ -754,7 +760,7 @@ CopyGetInt32(CopyState cstate, int32 *val)
754760/*
755761 * CopySendInt16 sends an int16 in network byte order
756762 */
757- static void
763+ static inline void
758764CopySendInt16 (CopyState cstate ,int16 val )
759765{
760766uint16 buf ;
@@ -766,12 +772,12 @@ CopySendInt16(CopyState cstate, int16 val)
766772/*
767773 * CopyGetInt16 reads an int16 that appears in network byte order
768774 */
769- static bool
775+ static inline bool
770776CopyGetInt16 (CopyState cstate ,int16 * val )
771777{
772778uint16 buf ;
773779
774- if (CopyGetData (cstate ,& buf , sizeof ( buf ) ,sizeof (buf ))!= sizeof (buf ))
780+ if (CopyReadBinaryData (cstate ,( char * ) & buf ,sizeof (buf ))!= sizeof (buf ))
775781{
776782* val = 0 ;/* suppress compiler warning */
777783return false;
@@ -786,26 +792,20 @@ CopyGetInt16(CopyState cstate, int16 *val)
786792 *
787793 * Returns true if able to obtain at least one more byte, else false.
788794 *
789- * If raw_buf_index < raw_buf_len, the unprocessed bytes are transferred
790- * down to the start of the buffer and then we load more data after that.
791- * This case is used only when a frontend multibyte character crosses a
792- * bufferload boundary.
795+ * If RAW_BUF_BYTES(cstate) > 0, the unprocessed bytes are moved to the start
796+ * of the buffer and then we load more data after that. This case occurs only
797+ * when a multibyte character crosses a bufferload boundary.
793798 */
794799static bool
795800CopyLoadRawBuf (CopyState cstate )
796801{
797- int nbytes ;
802+ int nbytes = RAW_BUF_BYTES ( cstate ) ;
798803int inbytes ;
799804
800- if (cstate -> raw_buf_index < cstate -> raw_buf_len )
801- {
802- /* Copy down the unprocessed data */
803- nbytes = cstate -> raw_buf_len - cstate -> raw_buf_index ;
805+ /* Copy down the unprocessed data if any. */
806+ if (nbytes > 0 )
804807memmove (cstate -> raw_buf ,cstate -> raw_buf + cstate -> raw_buf_index ,
805808nbytes );
806- }
807- else
808- nbytes = 0 ;/* no data need be saved */
809809
810810inbytes = CopyGetData (cstate ,cstate -> raw_buf + nbytes ,
8118111 ,RAW_BUF_SIZE - nbytes );
@@ -816,6 +816,54 @@ CopyLoadRawBuf(CopyState cstate)
816816return (inbytes > 0 );
817817}
818818
819+ /*
820+ * CopyReadBinaryData
821+ *
822+ * Reads up to 'nbytes' bytes from cstate->copy_file via cstate->raw_buf
823+ * and writes them to 'dest'. Returns the number of bytes read (which
824+ * would be less than 'nbytes' only if we reach EOF).
825+ */
826+ static int
827+ CopyReadBinaryData (CopyState cstate ,char * dest ,int nbytes )
828+ {
829+ int copied_bytes = 0 ;
830+
831+ if (RAW_BUF_BYTES (cstate ) >=nbytes )
832+ {
833+ /* Enough bytes are present in the buffer. */
834+ memcpy (dest ,cstate -> raw_buf + cstate -> raw_buf_index ,nbytes );
835+ cstate -> raw_buf_index += nbytes ;
836+ copied_bytes = nbytes ;
837+ }
838+ else
839+ {
840+ /*
841+ * Not enough bytes in the buffer, so must read from the file. Need
842+ * to loop since 'nbytes' could be larger than the buffer size.
843+ */
844+ do
845+ {
846+ int copy_bytes ;
847+
848+ /* Load more data if buffer is empty. */
849+ if (RAW_BUF_BYTES (cstate )== 0 )
850+ {
851+ if (!CopyLoadRawBuf (cstate ))
852+ break ;/* EOF */
853+ }
854+
855+ /* Transfer some bytes. */
856+ copy_bytes = Min (nbytes - copied_bytes ,RAW_BUF_BYTES (cstate ));
857+ memcpy (dest ,cstate -> raw_buf + cstate -> raw_buf_index ,copy_bytes );
858+ cstate -> raw_buf_index += copy_bytes ;
859+ dest += copy_bytes ;
860+ copied_bytes += copy_bytes ;
861+ }while (copied_bytes < nbytes );
862+ }
863+
864+ return copied_bytes ;
865+ }
866+
819867
820868/*
821869 * DoCopy executes the SQL COPY statement
@@ -3366,17 +3414,17 @@ BeginCopyFrom(ParseState *pstate,
33663414cstate -> cur_attval = NULL ;
33673415
33683416/*
3369- * Set up variables to avoid per-attribute overhead. attribute_bufis
3370- * used in both text and binary modes, but we use line_buf and raw_buf
3417+ * Set up variables to avoid per-attribute overhead. attribute_bufand
3418+ *raw_buf are used in both text and binary modes, but we use line_buf
33713419 * only in text mode.
33723420 */
33733421initStringInfo (& cstate -> attribute_buf );
3422+ cstate -> raw_buf = (char * )palloc (RAW_BUF_SIZE + 1 );
3423+ cstate -> raw_buf_index = cstate -> raw_buf_len = 0 ;
33743424if (!cstate -> binary )
33753425{
33763426initStringInfo (& cstate -> line_buf );
33773427cstate -> line_buf_converted = false;
3378- cstate -> raw_buf = (char * )palloc (RAW_BUF_SIZE + 1 );
3379- cstate -> raw_buf_index = cstate -> raw_buf_len = 0 ;
33803428}
33813429
33823430/* Assign range table, we'll need it in CopyFrom. */
@@ -3527,7 +3575,7 @@ BeginCopyFrom(ParseState *pstate,
35273575int32 tmp ;
35283576
35293577/* Signature */
3530- if (CopyGetData (cstate ,readSig , 11 ,11 )!= 11 ||
3578+ if (CopyReadBinaryData (cstate ,readSig ,11 )!= 11 ||
35313579memcmp (readSig ,BinarySignature ,11 )!= 0 )
35323580ereport (ERROR ,
35333581(errcode (ERRCODE_BAD_COPY_FILE_FORMAT ),
@@ -3555,7 +3603,7 @@ BeginCopyFrom(ParseState *pstate,
35553603/* Skip extension header, if present */
35563604while (tmp -- > 0 )
35573605{
3558- if (CopyGetData (cstate ,readSig , 1 ,1 )!= 1 )
3606+ if (CopyReadBinaryData (cstate ,readSig ,1 )!= 1 )
35593607ereport (ERROR ,
35603608(errcode (ERRCODE_BAD_COPY_FILE_FORMAT ),
35613609errmsg ("invalid COPY file header (wrong length)" )));
@@ -3771,7 +3819,7 @@ NextCopyFrom(CopyState cstate, ExprContext *econtext,
37713819char dummy ;
37723820
37733821if (cstate -> copy_dest != COPY_OLD_FE &&
3774- CopyGetData (cstate ,& dummy , 1 ,1 )> 0 )
3822+ CopyReadBinaryData (cstate ,& dummy ,1 )> 0 )
37753823ereport (ERROR ,
37763824(errcode (ERRCODE_BAD_COPY_FILE_FORMAT ),
37773825errmsg ("received copy data after EOF marker" )));
@@ -4744,8 +4792,8 @@ CopyReadBinaryAttribute(CopyState cstate, FmgrInfo *flinfo,
47444792resetStringInfo (& cstate -> attribute_buf );
47454793
47464794enlargeStringInfo (& cstate -> attribute_buf ,fld_size );
4747- if (CopyGetData (cstate ,cstate -> attribute_buf .data ,
4748- fld_size , fld_size )!= fld_size )
4795+ if (CopyReadBinaryData (cstate ,cstate -> attribute_buf .data ,
4796+ fld_size )!= fld_size )
47494797ereport (ERROR ,
47504798(errcode (ERRCODE_BAD_COPY_FILE_FORMAT ),
47514799errmsg ("unexpected EOF in COPY data" )));