@@ -54,6 +54,14 @@ typedef enum CopyDest
5454COPY_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
97105MemoryContext copycontext ;/* per-copy execution context */
98106
99107FmgrInfo * out_functions ;/* lookup info for output functions */
108+ CopyAttributeOut copy_attribute_out ;/* output representation callback */
100109MemoryContext rowcontext ;/* per-row evaluation context */
101110uint64 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 */
434446ProcessCopyOptions (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 */
437458if (rel )
438459{
@@ -836,11 +857,8 @@ DoCopyTo(CopyToState cstate)
836857
837858colname = 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
846864CopySendEndOfRow (cstate );
@@ -950,12 +968,9 @@ CopyOneRowTo(CopyToState cstate, TupleTableSlot *slot)
950968{
951969string = OutputFunctionCall (& out_functions [attnum - 1 ],
952970value );
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}
960975else
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{
9901006const char * ptr ;
9911007const 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{
11441160const char * ptr ;
11451161const char * start ;
11461162char c ;
11471163char delimc = cstate -> opts .delim [0 ];
11481164char quotec = cstate -> opts .quote [0 ];
11491165char 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!) */
11521169if (!use_quote && strcmp (string ,cstate -> opts .null_print )== 0 )