Revert "Refactor CopyAttributeOut{CSV,Text}() to use a callback in COPY TO"

This reverts commit 2889fd23be, following a discussion with Andres
Freund as this callback, being called once per attribute when sending a
relation's row, can involve a lot of indirect function calls (more
attributes to deal with means more impact).  The effects of a dispatch
at this level would become more visible when improving the per-row code
execution of COPY TO, impacting future potential performance
improvements.

Discussion: https://postgr.es/m/20240206014125.qofww7ew3dx3v3uk@awork3.anarazel.de
This commit is contained in:
Michael Paquier 2024-02-07 08:04:26 +09:00
parent e4b27b5355
commit 1aa8324b81
1 changed files with 15 additions and 32 deletions

View File

@ -54,14 +54,6 @@ typedef enum CopyDest
COPY_CALLBACK, /* to callback function */ COPY_CALLBACK, /* to callback function */
} CopyDest; } CopyDest;
/*
* Per-format callback to send output representation of one attribute for
* a `string`. `use_quote` tracks if quotes are required in the output
* representation.
*/
typedef void (*CopyAttributeOut) (CopyToState cstate, const char *string,
bool use_quote);
/* /*
* This struct contains all the state variables used throughout a COPY TO * This struct contains all the state variables used throughout a COPY TO
* operation. * operation.
@ -105,7 +97,6 @@ typedef struct CopyToStateData
MemoryContext copycontext; /* per-copy execution context */ MemoryContext copycontext; /* per-copy execution context */
FmgrInfo *out_functions; /* lookup info for output functions */ FmgrInfo *out_functions; /* lookup info for output functions */
CopyAttributeOut copy_attribute_out; /* output representation callback */
MemoryContext rowcontext; /* per-row evaluation context */ MemoryContext rowcontext; /* per-row evaluation context */
uint64 bytes_processed; /* number of bytes processed so far */ uint64 bytes_processed; /* number of bytes processed so far */
} CopyToStateData; } CopyToStateData;
@ -126,12 +117,9 @@ static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
static void EndCopy(CopyToState cstate); static void EndCopy(CopyToState cstate);
static void ClosePipeToProgram(CopyToState cstate); static void ClosePipeToProgram(CopyToState cstate);
static void CopyOneRowTo(CopyToState cstate, TupleTableSlot *slot); static void CopyOneRowTo(CopyToState cstate, TupleTableSlot *slot);
static void CopyAttributeOutText(CopyToState cstate, const char *string);
/* Callbacks for copy_attribute_out */
static void CopyAttributeOutText(CopyToState cstate, const char *string,
bool use_quote);
static void CopyAttributeOutCSV(CopyToState cstate, const char *string, static void CopyAttributeOutCSV(CopyToState cstate, const char *string,
bool use_quote); bool use_quote, bool single_attr);
/* Low-level communications functions */ /* Low-level communications functions */
static void SendCopyBegin(CopyToState cstate); static void SendCopyBegin(CopyToState cstate);
@ -445,15 +433,6 @@ BeginCopyTo(ParseState *pstate,
/* Extract options from the statement node tree */ /* Extract options from the statement node tree */
ProcessCopyOptions(pstate, &cstate->opts, false /* is_from */ , options); ProcessCopyOptions(pstate, &cstate->opts, false /* is_from */ , options);
/* Set output representation callback */
if (!cstate->opts.binary)
{
if (cstate->opts.csv_mode)
cstate->copy_attribute_out = CopyAttributeOutCSV;
else
cstate->copy_attribute_out = CopyAttributeOutText;
}
/* Process the source/target relation or query */ /* Process the source/target relation or query */
if (rel) if (rel)
{ {
@ -857,8 +836,11 @@ DoCopyTo(CopyToState cstate)
colname = NameStr(TupleDescAttr(tupDesc, attnum - 1)->attname); colname = NameStr(TupleDescAttr(tupDesc, attnum - 1)->attname);
/* Ignore quotes */ if (cstate->opts.csv_mode)
cstate->copy_attribute_out(cstate, colname, false); CopyAttributeOutCSV(cstate, colname, false,
list_length(cstate->attnumlist) == 1);
else
CopyAttributeOutText(cstate, colname);
} }
CopySendEndOfRow(cstate); CopySendEndOfRow(cstate);
@ -968,9 +950,12 @@ CopyOneRowTo(CopyToState cstate, TupleTableSlot *slot)
{ {
string = OutputFunctionCall(&out_functions[attnum - 1], string = OutputFunctionCall(&out_functions[attnum - 1],
value); value);
if (cstate->opts.csv_mode)
cstate->copy_attribute_out(cstate, string, CopyAttributeOutCSV(cstate, string,
cstate->opts.force_quote_flags[attnum - 1]); cstate->opts.force_quote_flags[attnum - 1],
list_length(cstate->attnumlist) == 1);
else
CopyAttributeOutText(cstate, string);
} }
else else
{ {
@ -1000,8 +985,7 @@ CopyOneRowTo(CopyToState cstate, TupleTableSlot *slot)
} while (0) } while (0)
static void static void
CopyAttributeOutText(CopyToState cstate, const char *string, CopyAttributeOutText(CopyToState cstate, const char *string)
bool use_quote)
{ {
const char *ptr; const char *ptr;
const char *start; const char *start;
@ -1155,7 +1139,7 @@ CopyAttributeOutText(CopyToState cstate, const char *string,
*/ */
static void static void
CopyAttributeOutCSV(CopyToState cstate, const char *string, CopyAttributeOutCSV(CopyToState cstate, const char *string,
bool use_quote) bool use_quote, bool single_attr)
{ {
const char *ptr; const char *ptr;
const char *start; const char *start;
@ -1163,7 +1147,6 @@ CopyAttributeOutCSV(CopyToState cstate, const char *string,
char delimc = cstate->opts.delim[0]; char delimc = cstate->opts.delim[0];
char quotec = cstate->opts.quote[0]; char quotec = cstate->opts.quote[0];
char escapec = cstate->opts.escape[0]; char escapec = cstate->opts.escape[0];
bool single_attr = (list_length(cstate->attnumlist) == 1);
/* force quoting if it matches null_print (before conversion!) */ /* force quoting if it matches null_print (before conversion!) */
if (!use_quote && strcmp(string, cstate->opts.null_print) == 0) if (!use_quote && strcmp(string, cstate->opts.null_print) == 0)