@@ -54,6 +54,14 @@ typedef enum CopyDest
5454 COPY_CALLBACK , /* to callback function */
5555} CopyDest ;
5656
57+ /*
58+ * Per-format callback to send output representation of one attribute for
59+ * a `string`. `use_quote` tracks if quotes are required in the output
60+ * representation.
61+ */
62+ typedef void (* CopyAttributeOut ) (CopyToState cstate , const char * string ,
63+ bool use_quote );
64+
5765/*
5866 * This struct contains all the state variables used throughout a COPY TO
5967 * operation.
@@ -97,6 +105,7 @@ typedef struct CopyToStateData
97105 MemoryContext copycontext ; /* per-copy execution context */
98106
99107 FmgrInfo * out_functions ; /* lookup info for output functions */
108+ CopyAttributeOut copy_attribute_out ; /* output representation callback */
100109 MemoryContext rowcontext ; /* per-row evaluation context */
101110 uint64 bytes_processed ; /* number of bytes processed so far */
102111} CopyToStateData ;
@@ -117,9 +126,12 @@ static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
117126static void EndCopy (CopyToState cstate );
118127static void ClosePipeToProgram (CopyToState cstate );
119128static void CopyOneRowTo (CopyToState cstate , TupleTableSlot * slot );
120- static void CopyAttributeOutText (CopyToState cstate , const char * string );
129+
130+ /* Callbacks for copy_attribute_out */
131+ static void CopyAttributeOutText (CopyToState cstate , const char * string ,
132+ bool use_quote );
121133static void CopyAttributeOutCSV (CopyToState cstate , const char * string ,
122- bool use_quote , bool single_attr );
134+ bool use_quote );
123135
124136/* Low-level communications functions */
125137static void SendCopyBegin (CopyToState cstate );
@@ -433,6 +445,15 @@ BeginCopyTo(ParseState *pstate,
433445 /* Extract options from the statement node tree */
434446 ProcessCopyOptions (pstate , & cstate -> opts , false /* is_from */ , options );
435447
448+ /* Set output representation callback */
449+ if (!cstate -> opts .binary )
450+ {
451+ if (cstate -> opts .csv_mode )
452+ cstate -> copy_attribute_out = CopyAttributeOutCSV ;
453+ else
454+ cstate -> copy_attribute_out = CopyAttributeOutText ;
455+ }
456+
436457 /* Process the source/target relation or query */
437458 if (rel )
438459 {
@@ -836,11 +857,8 @@ DoCopyTo(CopyToState cstate)
836857
837858 colname = NameStr (TupleDescAttr (tupDesc , attnum - 1 )-> attname );
838859
839- if (cstate -> opts .csv_mode )
840- CopyAttributeOutCSV (cstate , colname , false,
841- list_length (cstate -> attnumlist ) == 1 );
842- else
843- CopyAttributeOutText (cstate , colname );
860+ /* Ignore quotes */
861+ cstate -> copy_attribute_out (cstate , colname , false);
844862 }
845863
846864 CopySendEndOfRow (cstate );
@@ -950,12 +968,9 @@ CopyOneRowTo(CopyToState cstate, TupleTableSlot *slot)
950968 {
951969 string = OutputFunctionCall (& out_functions [attnum - 1 ],
952970 value );
953- if (cstate -> opts .csv_mode )
954- CopyAttributeOutCSV (cstate , string ,
955- cstate -> opts .force_quote_flags [attnum - 1 ],
956- list_length (cstate -> attnumlist ) == 1 );
957- else
958- CopyAttributeOutText (cstate , string );
971+
972+ cstate -> copy_attribute_out (cstate , string ,
973+ cstate -> opts .force_quote_flags [attnum - 1 ]);
959974 }
960975 else
961976 {
@@ -985,7 +1000,8 @@ CopyOneRowTo(CopyToState cstate, TupleTableSlot *slot)
9851000 } while (0)
9861001
9871002static void
988- CopyAttributeOutText (CopyToState cstate , const char * string )
1003+ CopyAttributeOutText (CopyToState cstate , const char * string ,
1004+ bool use_quote )
9891005{
9901006 const char * ptr ;
9911007 const char * start ;
@@ -1139,14 +1155,15 @@ CopyAttributeOutText(CopyToState cstate, const char *string)
11391155 */
11401156static void
11411157CopyAttributeOutCSV (CopyToState cstate , const char * string ,
1142- bool use_quote , bool single_attr )
1158+ bool use_quote )
11431159{
11441160 const char * ptr ;
11451161 const char * start ;
11461162 char c ;
11471163 char delimc = cstate -> opts .delim [0 ];
11481164 char quotec = cstate -> opts .quote [0 ];
11491165 char escapec = cstate -> opts .escape [0 ];
1166+ bool single_attr = (list_length (cstate -> attnumlist ) == 1 );
11501167
11511168 /* force quoting if it matches null_print (before conversion!) */
11521169 if (!use_quote && strcmp (string , cstate -> opts .null_print ) == 0 )
0 commit comments