From 0d91cd0a278419963e1e7dcf2cdf4d0630d1efb6 Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Tue, 3 Oct 2017 00:36:42 -0700
Subject: [PATCH 4/6] Use one stringbuffer for all rows printed in printtup.c.

This avoids newly allocating, and then possibly growing, the
stringbuffer for every row. For wide rows this can substantially
reduce memory allocator overhead, at the price of not immediately
reducing memory usage after outputting an especially wide row.
---
 src/backend/access/common/printtup.c | 45 +++++++++++++++++++-----------------
 1 file changed, 24 insertions(+), 21 deletions(-)

diff --git a/src/backend/access/common/printtup.c b/src/backend/access/common/printtup.c
index 20d20e623e8..bb807239b5a 100644
--- a/src/backend/access/common/printtup.c
+++ b/src/backend/access/common/printtup.c
@@ -57,6 +57,7 @@ typedef struct
 typedef struct
 {
 	DestReceiver pub;			/* publicly-known function pointers */
+	StringInfoData buf;			/* output buffer */
 	Portal		portal;			/* the Portal we are printing from */
 	bool		sendDescrip;	/* send RowDescription at startup? */
 	TupleDesc	attrinfo;		/* The attr info we are set up for */
@@ -251,6 +252,8 @@ printtup_prepare_info(DR_printtup *myState, TupleDesc typeinfo, int numAttrs)
 	int16	   *formats = myState->portal->formats;
 	int			i;
 
+	initStringInfo(&myState->buf);
+
 	/* get rid of any old data */
 	if (myState->myinfo)
 		pfree(myState->myinfo);
@@ -302,7 +305,7 @@ printtup(TupleTableSlot *slot, DestReceiver *self)
 	TupleDesc	typeinfo = slot->tts_tupleDescriptor;
 	DR_printtup *myState = (DR_printtup *) self;
 	MemoryContext oldcontext;
-	StringInfoData buf;
+	StringInfo	buf = &myState->buf;
 	int			natts = typeinfo->natts;
 	int			i;
 
@@ -319,9 +322,9 @@ printtup(TupleTableSlot *slot, DestReceiver *self)
 	/*
 	 * Prepare a DataRow message (note buffer is in per-row context)
 	 */
-	pq_beginmessage(&buf, 'D');
+	pq_beginmessage_reuse(buf, 'D');
 
-	pq_sendint(&buf, natts, 2);
+	pq_sendint(buf, natts, 2);
 
 	/*
 	 * send the attributes of this tuple
@@ -333,7 +336,7 @@ printtup(TupleTableSlot *slot, DestReceiver *self)
 
 		if (slot->tts_isnull[i])
 		{
-			pq_sendint(&buf, -1, 4);
+			pq_sendint(buf, -1, 4);
 			continue;
 		}
 
@@ -354,7 +357,7 @@ printtup(TupleTableSlot *slot, DestReceiver *self)
 			char	   *outputstr;
 
 			outputstr = OutputFunctionCall(&thisState->finfo, attr);
-			pq_sendcountedtext(&buf, outputstr, strlen(outputstr), false);
+			pq_sendcountedtext(buf, outputstr, strlen(outputstr), false);
 		}
 		else
 		{
@@ -362,13 +365,13 @@ printtup(TupleTableSlot *slot, DestReceiver *self)
 			bytea	   *outputbytes;
 
 			outputbytes = SendFunctionCall(&thisState->finfo, attr);
-			pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
-			pq_sendbytes(&buf, VARDATA(outputbytes),
+			pq_sendint(buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
+			pq_sendbytes(buf, VARDATA(outputbytes),
 						 VARSIZE(outputbytes) - VARHDRSZ);
 		}
 	}
 
-	pq_endmessage(&buf);
+	pq_endmessage_reuse(buf);
 
 	/* Return to caller's context, and flush row's temporary memory */
 	MemoryContextSwitchTo(oldcontext);
@@ -387,7 +390,7 @@ printtup_20(TupleTableSlot *slot, DestReceiver *self)
 	TupleDesc	typeinfo = slot->tts_tupleDescriptor;
 	DR_printtup *myState = (DR_printtup *) self;
 	MemoryContext oldcontext;
-	StringInfoData buf;
+	StringInfo	buf = &myState->buf;
 	int			natts = typeinfo->natts;
 	int			i,
 				j,
@@ -406,7 +409,7 @@ printtup_20(TupleTableSlot *slot, DestReceiver *self)
 	/*
 	 * tell the frontend to expect new tuple data (in ASCII style)
 	 */
-	pq_beginmessage(&buf, 'D');
+	pq_beginmessage_reuse(buf, 'D');
 
 	/*
 	 * send a bitmap of which attributes are not null
@@ -420,13 +423,13 @@ printtup_20(TupleTableSlot *slot, DestReceiver *self)
 		k >>= 1;
 		if (k == 0)				/* end of byte? */
 		{
-			pq_sendint(&buf, j, 1);
+			pq_sendint(buf, j, 1);
 			j = 0;
 			k = 1 << 7;
 		}
 	}
 	if (k != (1 << 7))			/* flush last partial byte */
-		pq_sendint(&buf, j, 1);
+		pq_sendint(buf, j, 1);
 
 	/*
 	 * send the attributes of this tuple
@@ -443,10 +446,10 @@ printtup_20(TupleTableSlot *slot, DestReceiver *self)
 		Assert(thisState->format == 0);
 
 		outputstr = OutputFunctionCall(&thisState->finfo, attr);
-		pq_sendcountedtext(&buf, outputstr, strlen(outputstr), true);
+		pq_sendcountedtext(buf, outputstr, strlen(outputstr), true);
 	}
 
-	pq_endmessage(&buf);
+	pq_endmessage_reuse(buf);
 
 	/* Return to caller's context, and flush row's temporary memory */
 	MemoryContextSwitchTo(oldcontext);
@@ -572,7 +575,7 @@ printtup_internal_20(TupleTableSlot *slot, DestReceiver *self)
 	TupleDesc	typeinfo = slot->tts_tupleDescriptor;
 	DR_printtup *myState = (DR_printtup *) self;
 	MemoryContext oldcontext;
-	StringInfoData buf;
+	StringInfo	buf = &myState->buf;
 	int			natts = typeinfo->natts;
 	int			i,
 				j,
@@ -591,7 +594,7 @@ printtup_internal_20(TupleTableSlot *slot, DestReceiver *self)
 	/*
 	 * tell the frontend to expect new tuple data (in binary style)
 	 */
-	pq_beginmessage(&buf, 'B');
+	pq_beginmessage_reuse(buf, 'B');
 
 	/*
 	 * send a bitmap of which attributes are not null
@@ -605,13 +608,13 @@ printtup_internal_20(TupleTableSlot *slot, DestReceiver *self)
 		k >>= 1;
 		if (k == 0)				/* end of byte? */
 		{
-			pq_sendint(&buf, j, 1);
+			pq_sendint(buf, j, 1);
 			j = 0;
 			k = 1 << 7;
 		}
 	}
 	if (k != (1 << 7))			/* flush last partial byte */
-		pq_sendint(&buf, j, 1);
+		pq_sendint(buf, j, 1);
 
 	/*
 	 * send the attributes of this tuple
@@ -628,12 +631,12 @@ printtup_internal_20(TupleTableSlot *slot, DestReceiver *self)
 		Assert(thisState->format == 1);
 
 		outputbytes = SendFunctionCall(&thisState->finfo, attr);
-		pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
-		pq_sendbytes(&buf, VARDATA(outputbytes),
+		pq_sendint(buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
+		pq_sendbytes(buf, VARDATA(outputbytes),
 					 VARSIZE(outputbytes) - VARHDRSZ);
 	}
 
-	pq_endmessage(&buf);
+	pq_endmessage_reuse(buf);
 
 	/* Return to caller's context, and flush row's temporary memory */
 	MemoryContextSwitchTo(oldcontext);
-- 
2.14.1.536.g6867272d5b.dirty

