]> granicus.if.org Git - postgresql/commitdiff
Use one stringbuffer for all rows printed in printtup.c.
authorAndres Freund <andres@anarazel.de>
Wed, 11 Oct 2017 23:26:35 +0000 (16:26 -0700)
committerAndres Freund <andres@anarazel.de>
Wed, 11 Oct 2017 23:26:35 +0000 (16:26 -0700)
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.

Author: Andres Freund
Discussion: https://postgr.es/m/20170914063418.sckdzgjfrsbekae4@alap3.anarazel.de

src/backend/access/common/printtup.c

index 20d20e623e80d805395ecd9f32a2bacaf51f1294..c00b372b849ad7eb355afc1e675408714922c31a 100644 (file)
@@ -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 */
@@ -127,6 +128,9 @@ printtup_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
        DR_printtup *myState = (DR_printtup *) self;
        Portal          portal = myState->portal;
 
+       /* create buffer to be used for all messages */
+       initStringInfo(&myState->buf);
+
        /*
         * Create a temporary memory context that we can reset once per row to
         * recover palloc'd memory.  This avoids any problems with leaks inside
@@ -302,7 +306,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 +323,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 +337,7 @@ printtup(TupleTableSlot *slot, DestReceiver *self)
 
                if (slot->tts_isnull[i])
                {
-                       pq_sendint(&buf, -1, 4);
+                       pq_sendint(buf, -1, 4);
                        continue;
                }
 
@@ -354,7 +358,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 +366,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 +391,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 +410,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 +424,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 +447,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 +576,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 +595,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 +609,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 +632,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);