Commit f2004f19 authored by Tom Lane's avatar Tom Lane

Fix memory leak in printtup.c.

Commit f2dec34e changed things so that printtup's output stringinfo
buffer was allocated outside the per-row temporary context, not inside
it.  This creates a need to free that buffer explicitly when the temp
context is freed, but that was overlooked.  In most cases, this is all
happening inside a portal or executor context that will go away shortly
anyhow, but that's not always true.  Notably, the stringinfo ends up
getting leaked when JDBC uses row-at-a-time fetches.  For a query
that returns wide rows, that adds up after awhile.

Per bug #15700 from Matthias Otterbach.  Back-patch to v11 where the
faulty code was added.

Discussion: https://postgr.es/m/15700-8c408321a87d56bb@postgresql.org
parent 11180a50
...@@ -61,12 +61,12 @@ typedef struct ...@@ -61,12 +61,12 @@ typedef struct
typedef struct typedef struct
{ {
DestReceiver pub; /* publicly-known function pointers */ DestReceiver pub; /* publicly-known function pointers */
StringInfoData buf; /* output buffer */
Portal portal; /* the Portal we are printing from */ Portal portal; /* the Portal we are printing from */
bool sendDescrip; /* send RowDescription at startup? */ bool sendDescrip; /* send RowDescription at startup? */
TupleDesc attrinfo; /* The attr info we are set up for */ TupleDesc attrinfo; /* The attr info we are set up for */
int nattrs; int nattrs;
PrinttupAttrInfo *myinfo; /* Cached info about each attr */ PrinttupAttrInfo *myinfo; /* Cached info about each attr */
StringInfoData buf; /* output buffer (*not* in tmpcontext) */
MemoryContext tmpcontext; /* Memory context for per-row workspace */ MemoryContext tmpcontext; /* Memory context for per-row workspace */
} DR_printtup; } DR_printtup;
...@@ -94,6 +94,7 @@ printtup_create_DR(CommandDest dest) ...@@ -94,6 +94,7 @@ printtup_create_DR(CommandDest dest)
self->attrinfo = NULL; self->attrinfo = NULL;
self->nattrs = 0; self->nattrs = 0;
self->myinfo = NULL; self->myinfo = NULL;
self->buf.data = NULL;
self->tmpcontext = NULL; self->tmpcontext = NULL;
return (DestReceiver *) self; return (DestReceiver *) self;
...@@ -132,7 +133,10 @@ printtup_startup(DestReceiver *self, int operation, TupleDesc typeinfo) ...@@ -132,7 +133,10 @@ printtup_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
DR_printtup *myState = (DR_printtup *) self; DR_printtup *myState = (DR_printtup *) self;
Portal portal = myState->portal; Portal portal = myState->portal;
/* create buffer to be used for all messages */ /*
* Create I/O buffer to be used for all messages. This cannot be inside
* tmpcontext, since we want to re-use it across rows.
*/
initStringInfo(&myState->buf); initStringInfo(&myState->buf);
/* /*
...@@ -544,6 +548,10 @@ printtup_shutdown(DestReceiver *self) ...@@ -544,6 +548,10 @@ printtup_shutdown(DestReceiver *self)
myState->attrinfo = NULL; myState->attrinfo = NULL;
if (myState->buf.data)
pfree(myState->buf.data);
myState->buf.data = NULL;
if (myState->tmpcontext) if (myState->tmpcontext)
MemoryContextDelete(myState->tmpcontext); MemoryContextDelete(myState->tmpcontext);
myState->tmpcontext = NULL; myState->tmpcontext = NULL;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment