From 6f505a0b94564ad2dfa628f61ddee7c9178c4df0 Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Tue, 6 Feb 2024 14:50:46 -0800
Subject: [PATCH v13a 3/3] WIP: Remove out callback

---
 src/backend/commands/copyto.c | 66 ++++++++++++++++++++---------------
 1 file changed, 37 insertions(+), 29 deletions(-)

diff --git a/src/backend/commands/copyto.c b/src/backend/commands/copyto.c
index 8923627d9ad..8cbcc399ea0 100644
--- a/src/backend/commands/copyto.c
+++ b/src/backend/commands/copyto.c
@@ -55,14 +55,6 @@ typedef enum CopyDest
 	COPY_CALLBACK,				/* to callback function */
 } 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
  * operation.
@@ -109,7 +101,6 @@ typedef struct CopyToStateData
 	MemoryContext copycontext;	/* per-copy execution context */
 
 	FmgrInfo   *out_functions;	/* lookup info for output functions */
-	CopyAttributeOut copy_attribute_out;	/* output representation callback */
 	MemoryContext rowcontext;	/* per-row evaluation context */
 	uint64		bytes_processed;	/* number of bytes processed so far */
 } CopyToStateData;
@@ -131,9 +122,8 @@ static void EndCopy(CopyToState cstate);
 static void ClosePipeToProgram(CopyToState cstate);
 static void CopyOneRowTo(CopyToState cstate, TupleTableSlot *slot);
 
-/* Callbacks for copy_attribute_out */
-static void CopyAttributeOutText(CopyToState cstate, const char *string,
-								 bool use_quote);
+/* Helpers for for CopyToTextStart / CopyToTextLikeOneRow */
+static void CopyAttributeOutText(CopyToState cstate, const char *string);
 static void CopyAttributeOutCSV(CopyToState cstate, const char *string,
 								bool use_quote);
 
@@ -192,12 +182,6 @@ CopyToTextStart(CopyToState cstate, TupleDesc tupDesc)
 {
 	ListCell   *cur;
 
-	/* Set output representation callback */
-	if (cstate->opts.csv_mode)
-		cstate->copy_attribute_out = CopyAttributeOutCSV;
-	else
-		cstate->copy_attribute_out = CopyAttributeOutText;
-
 	/*
 	 * For non-binary copy, we need to convert null_print to file encoding,
 	 * because it will be sent directly with CopySendString.
@@ -224,7 +208,10 @@ CopyToTextStart(CopyToState cstate, TupleDesc tupDesc)
 			colname = NameStr(TupleDescAttr(tupDesc, attnum - 1)->attname);
 
 			/* Ignore quotes */
-			cstate->copy_attribute_out(cstate, colname, false);
+			if (cstate->opts.csv_mode)
+				CopyAttributeOutCSV(cstate, colname, false);
+			else
+				CopyAttributeOutText(cstate, colname);
 		}
 
 		CopyToTextSendEndOfRow(cstate);
@@ -248,13 +235,16 @@ CopyToTextOutFunc(CopyToState cstate, Oid atttypid, FmgrInfo *finfo)
 }
 
 /*
- * CopyToTextOneRow
+ * CopyToTextLikeOneRow
  *
- * Process one row for text/CSV format.
+ * Process one row for text/CSV format. This is intended to be used by callers
+ * that pass in a constant value for is_csv, allowing the compiler to optimize
+ * relevant branches away.
  */
-static void
-CopyToTextOneRow(CopyToState cstate,
-				 TupleTableSlot *slot)
+static pg_attribute_always_inline void
+CopyToTextLikeOneRow(CopyToState cstate,
+					 TupleTableSlot *slot,
+					 bool is_csv)
 {
 	bool		need_delim = false;
 	FmgrInfo   *out_functions = cstate->out_functions;
@@ -280,14 +270,33 @@ CopyToTextOneRow(CopyToState cstate,
 
 			string = OutputFunctionCall(&out_functions[attnum - 1], value);
 
-			cstate->copy_attribute_out(cstate, string,
-									   cstate->opts.force_quote_flags[attnum - 1]);
+			/* optimized away by compiler, argument is constant at caller */
+			if (is_csv)
+				CopyAttributeOutCSV(cstate, string,
+									cstate->opts.force_quote_flags[attnum - 1]);
+			else
+				CopyAttributeOutText(cstate, string);
 		}
 	}
 
 	CopyToTextSendEndOfRow(cstate);
 }
 
+static void
+CopyToTextOneRow(CopyToState cstate,
+				 TupleTableSlot *slot)
+{
+	CopyToTextLikeOneRow(cstate, slot, false);
+}
+
+static void
+CopyToCSVOneRow(CopyToState cstate,
+				 TupleTableSlot *slot)
+{
+	CopyToTextLikeOneRow(cstate, slot, true);
+}
+
+
 /*
  * CopyToTextEnd
  *
@@ -406,7 +415,7 @@ static const CopyToRoutine CopyToRoutineText = {
 static const CopyToRoutine CopyToRoutineCSV = {
 	.CopyToStart = CopyToTextStart,
 	.CopyToOutFunc = CopyToTextOutFunc,
-	.CopyToOneRow = CopyToTextOneRow,
+	.CopyToOneRow = CopyToCSVOneRow,
 	.CopyToEnd = CopyToTextEnd,
 };
 
@@ -1155,8 +1164,7 @@ CopyOneRowTo(CopyToState cstate, TupleTableSlot *slot)
 	} while (0)
 
 static void
-CopyAttributeOutText(CopyToState cstate, const char *string,
-					 bool use_quote)
+CopyAttributeOutText(CopyToState cstate, const char *string)
 {
 	const char *ptr;
 	const char *start;
-- 
2.38.0

