@@ -187,15 +187,15 @@ typedef struct CopyStateData
187
187
TransitionCaptureState * transition_capture ;
188
188
189
189
/*
190
- * These variables are used to reduce overhead in textual COPY FROM.
190
+ * These variables are used to reduce overhead in COPY FROM.
191
191
*
192
192
* attribute_buf holds the separated, de-escaped text for each field of
193
193
* the current line. The CopyReadAttributes functions return arrays of
194
194
* pointers into this buffer. We avoid palloc/pfree overhead by re-using
195
195
* the buffer on each cycle.
196
196
*
197
- * ( In binary COPY FROM, attribute_buf holds the binary data for the
198
- * current field, while the other variables are not used.)
197
+ * In binary COPY FROM, attribute_buf holds the binary data for the
198
+ * current field, but the usage is otherwise similar.
199
199
*/
200
200
StringInfoData attribute_buf ;
201
201
@@ -209,23 +209,27 @@ typedef struct CopyStateData
209
209
* input cycle is first to read the whole line into line_buf, convert it
210
210
* to server encoding there, and then extract the individual attribute
211
211
* 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.)
213
214
*/
214
215
StringInfoData line_buf ;
215
216
bool line_buf_converted ; /* converted to server encoding? */
216
217
bool line_buf_valid ; /* contains the row being processed? */
217
218
218
219
/*
219
220
* 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].
224
226
*/
225
227
#define RAW_BUF_SIZE 65536 /* we palloc RAW_BUF_SIZE+1 bytes */
226
228
char * raw_buf ;
227
229
int raw_buf_index ; /* next byte to process */
228
230
int 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)
229
233
} CopyStateData ;
230
234
231
235
/* DestReceiver for COPY (query) TO */
@@ -394,6 +398,8 @@ static void CopySendInt32(CopyState cstate, int32 val);
394
398
static bool CopyGetInt32 (CopyState cstate , int32 * val );
395
399
static void CopySendInt16 (CopyState cstate , int16 val );
396
400
static bool CopyGetInt16 (CopyState cstate , int16 * val );
401
+ static bool CopyLoadRawBuf (CopyState cstate );
402
+ static int CopyReadBinaryData (CopyState cstate , char * dest , int nbytes );
397
403
398
404
399
405
/*
@@ -723,7 +729,7 @@ CopyGetData(CopyState cstate, void *databuf, int minread, int maxread)
723
729
/*
724
730
* CopySendInt32 sends an int32 in network byte order
725
731
*/
726
- static void
732
+ static inline void
727
733
CopySendInt32 (CopyState cstate , int32 val )
728
734
{
729
735
uint32 buf ;
@@ -737,12 +743,12 @@ CopySendInt32(CopyState cstate, int32 val)
737
743
*
738
744
* Returns true if OK, false if EOF
739
745
*/
740
- static bool
746
+ static inline bool
741
747
CopyGetInt32 (CopyState cstate , int32 * val )
742
748
{
743
749
uint32 buf ;
744
750
745
- if (CopyGetData (cstate , & buf , sizeof ( buf ) , sizeof (buf )) != sizeof (buf ))
751
+ if (CopyReadBinaryData (cstate , ( char * ) & buf , sizeof (buf )) != sizeof (buf ))
746
752
{
747
753
* val = 0 ; /* suppress compiler warning */
748
754
return false;
@@ -754,7 +760,7 @@ CopyGetInt32(CopyState cstate, int32 *val)
754
760
/*
755
761
* CopySendInt16 sends an int16 in network byte order
756
762
*/
757
- static void
763
+ static inline void
758
764
CopySendInt16 (CopyState cstate , int16 val )
759
765
{
760
766
uint16 buf ;
@@ -766,12 +772,12 @@ CopySendInt16(CopyState cstate, int16 val)
766
772
/*
767
773
* CopyGetInt16 reads an int16 that appears in network byte order
768
774
*/
769
- static bool
775
+ static inline bool
770
776
CopyGetInt16 (CopyState cstate , int16 * val )
771
777
{
772
778
uint16 buf ;
773
779
774
- if (CopyGetData (cstate , & buf , sizeof ( buf ) , sizeof (buf )) != sizeof (buf ))
780
+ if (CopyReadBinaryData (cstate , ( char * ) & buf , sizeof (buf )) != sizeof (buf ))
775
781
{
776
782
* val = 0 ; /* suppress compiler warning */
777
783
return false;
@@ -786,26 +792,20 @@ CopyGetInt16(CopyState cstate, int16 *val)
786
792
*
787
793
* Returns true if able to obtain at least one more byte, else false.
788
794
*
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.
793
798
*/
794
799
static bool
795
800
CopyLoadRawBuf (CopyState cstate )
796
801
{
797
- int nbytes ;
802
+ int nbytes = RAW_BUF_BYTES ( cstate ) ;
798
803
int inbytes ;
799
804
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 )
804
807
memmove (cstate -> raw_buf , cstate -> raw_buf + cstate -> raw_buf_index ,
805
808
nbytes );
806
- }
807
- else
808
- nbytes = 0 ; /* no data need be saved */
809
809
810
810
inbytes = CopyGetData (cstate , cstate -> raw_buf + nbytes ,
811
811
1 , RAW_BUF_SIZE - nbytes );
@@ -816,6 +816,54 @@ CopyLoadRawBuf(CopyState cstate)
816
816
return (inbytes > 0 );
817
817
}
818
818
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
+
819
867
820
868
/*
821
869
* DoCopy executes the SQL COPY statement
@@ -3366,17 +3414,17 @@ BeginCopyFrom(ParseState *pstate,
3366
3414
cstate -> cur_attval = NULL ;
3367
3415
3368
3416
/*
3369
- * Set up variables to avoid per-attribute overhead. attribute_buf is
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_buf and
3418
+ * raw_buf are used in both text and binary modes, but we use line_buf
3371
3419
* only in text mode.
3372
3420
*/
3373
3421
initStringInfo (& cstate -> attribute_buf );
3422
+ cstate -> raw_buf = (char * ) palloc (RAW_BUF_SIZE + 1 );
3423
+ cstate -> raw_buf_index = cstate -> raw_buf_len = 0 ;
3374
3424
if (!cstate -> binary )
3375
3425
{
3376
3426
initStringInfo (& cstate -> line_buf );
3377
3427
cstate -> line_buf_converted = false;
3378
- cstate -> raw_buf = (char * ) palloc (RAW_BUF_SIZE + 1 );
3379
- cstate -> raw_buf_index = cstate -> raw_buf_len = 0 ;
3380
3428
}
3381
3429
3382
3430
/* Assign range table, we'll need it in CopyFrom. */
@@ -3527,7 +3575,7 @@ BeginCopyFrom(ParseState *pstate,
3527
3575
int32 tmp ;
3528
3576
3529
3577
/* Signature */
3530
- if (CopyGetData (cstate , readSig , 11 , 11 ) != 11 ||
3578
+ if (CopyReadBinaryData (cstate , readSig , 11 ) != 11 ||
3531
3579
memcmp (readSig , BinarySignature , 11 ) != 0 )
3532
3580
ereport (ERROR ,
3533
3581
(errcode (ERRCODE_BAD_COPY_FILE_FORMAT ),
@@ -3555,7 +3603,7 @@ BeginCopyFrom(ParseState *pstate,
3555
3603
/* Skip extension header, if present */
3556
3604
while (tmp -- > 0 )
3557
3605
{
3558
- if (CopyGetData (cstate , readSig , 1 , 1 ) != 1 )
3606
+ if (CopyReadBinaryData (cstate , readSig , 1 ) != 1 )
3559
3607
ereport (ERROR ,
3560
3608
(errcode (ERRCODE_BAD_COPY_FILE_FORMAT ),
3561
3609
errmsg ("invalid COPY file header (wrong length)" )));
@@ -3771,7 +3819,7 @@ NextCopyFrom(CopyState cstate, ExprContext *econtext,
3771
3819
char dummy ;
3772
3820
3773
3821
if (cstate -> copy_dest != COPY_OLD_FE &&
3774
- CopyGetData (cstate , & dummy , 1 , 1 ) > 0 )
3822
+ CopyReadBinaryData (cstate , & dummy , 1 ) > 0 )
3775
3823
ereport (ERROR ,
3776
3824
(errcode (ERRCODE_BAD_COPY_FILE_FORMAT ),
3777
3825
errmsg ("received copy data after EOF marker" )));
@@ -4744,8 +4792,8 @@ CopyReadBinaryAttribute(CopyState cstate, FmgrInfo *flinfo,
4744
4792
resetStringInfo (& cstate -> attribute_buf );
4745
4793
4746
4794
enlargeStringInfo (& 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 )
4749
4797
ereport (ERROR ,
4750
4798
(errcode (ERRCODE_BAD_COPY_FILE_FORMAT ),
4751
4799
errmsg ("unexpected EOF in COPY data" )));
0 commit comments