From bf6ae654768063f95e381145e9cf44969138c5dd Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Tue, 2 Jun 2020 16:47:26 -0700
Subject: [PATCH v3 07/10] wip: make send calls in printtup.c cheaper

Author:
Reviewed-By:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/backend/access/common/printtup.c | 40 +++++++++++++++++++++++++---
 1 file changed, 36 insertions(+), 4 deletions(-)

diff --git a/src/backend/access/common/printtup.c b/src/backend/access/common/printtup.c
index 8a4953ea033..b4c031f67e7 100644
--- a/src/backend/access/common/printtup.c
+++ b/src/backend/access/common/printtup.c
@@ -49,6 +49,15 @@ typedef struct
 	bool		typisvarlena;	/* is it varlena (ie possibly toastable)? */
 	int16		format;			/* format code for this column */
 	FmgrInfo	finfo;			/* Precomputed call info for output fn */
+
+	/* use union with FunctionCallInfoBaseData to guarantee alignment */
+	union
+	{
+		FunctionCallInfoBaseData fcinfo;
+		/* ensure enough space for nargs args is available */
+		char		fcinfo_data[SizeForFunctionCallInfo(1)];
+	}			fcinfo_data;
+
 } PrinttupAttrInfo;
 
 typedef struct
@@ -278,6 +287,9 @@ printtup_prepare_info(DR_printtup *myState, TupleDesc typeinfo, int numAttrs)
 							  &thisState->typoutput,
 							  &thisState->typisvarlena);
 			fmgr_info(thisState->typoutput, &thisState->finfo);
+			InitFunctionCallInfoData(thisState->fcinfo_data.fcinfo,
+									 &thisState->finfo, 1, InvalidOid,
+									 NULL, NULL);
 		}
 		else if (format == 1)
 		{
@@ -285,6 +297,9 @@ printtup_prepare_info(DR_printtup *myState, TupleDesc typeinfo, int numAttrs)
 									&thisState->typsend,
 									&thisState->typisvarlena);
 			fmgr_info(thisState->typsend, &thisState->finfo);
+			InitFunctionCallInfoData(thisState->fcinfo_data.fcinfo,
+									 &thisState->finfo, 1, InvalidOid,
+									 NULL, NULL);
 		}
 		else
 			ereport(ERROR,
@@ -361,11 +376,28 @@ printtup(TupleTableSlot *slot, DestReceiver *self)
 		{
 			/* Binary output */
 			bytea	   *outputbytes;
+			int			outputlen;
+			Datum		result;
+			FunctionCallInfo fcinfo = &thisState->fcinfo_data.fcinfo;
 
-			outputbytes = SendFunctionCall(&thisState->finfo, attr);
-			pq_sendint32(buf, VARSIZE(outputbytes) - VARHDRSZ);
-			pq_sendbytes(buf, VARDATA(outputbytes),
-						 VARSIZE(outputbytes) - VARHDRSZ);
+			fcinfo->args[0].value = attr;
+			fcinfo->args[0].isnull = false;
+			result = FunctionCallInvoke(fcinfo);
+
+			/*
+			 * Check for null result, since caller is clearly not expecting
+			 * one
+			 */
+			if (unlikely(fcinfo->isnull))
+				elog(ERROR, "send function return null");
+
+			outputbytes = DatumGetByteaP(result);
+			outputlen = VARSIZE(outputbytes) - VARHDRSZ;
+
+			Assert(outputlen > 0);
+
+			pq_sendint32(buf, outputlen);
+			pq_sendbytes(buf, VARDATA(outputbytes), outputlen);
 		}
 	}
 
-- 
2.38.0

