Skip to content

Commit 313de22

Browse files
committed
SQL functions returning pass-by-reference types were copying the results
into the wrong memory context, resulting in a query-lifespan memory leak. Bug is new in 8.0, I believe. Per report from Rae Stiening.
1 parent 9427cce commit 313de22

File tree

1 file changed

+22
-13
lines changed

1 file changed

+22
-13
lines changed

src/backend/executor/functions.c

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.96 2005/04/06 16:34:04 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.97 2005/04/10 18:04:20 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -86,12 +86,13 @@ static execution_state *init_execution_state(List *queryTree_list,
8686
static void init_sql_fcache(FmgrInfo *finfo);
8787
static void postquel_start(execution_state *es, SQLFunctionCachePtr fcache);
8888
static TupleTableSlot *postquel_getnext(execution_state *es);
89-
static void postquel_end(execution_state *es, SQLFunctionCachePtr fcache);
89+
static void postquel_end(execution_state *es);
9090
static void postquel_sub_params(SQLFunctionCachePtr fcache,
9191
FunctionCallInfo fcinfo);
9292
static Datum postquel_execute(execution_state *es,
9393
FunctionCallInfo fcinfo,
94-
SQLFunctionCachePtr fcache);
94+
SQLFunctionCachePtr fcache,
95+
MemoryContext resultcontext);
9596
static void sql_exec_error_callback(void *arg);
9697
static void ShutdownSQLFunction(Datum arg);
9798

@@ -384,7 +385,7 @@ postquel_getnext(execution_state *es)
384385
}
385386

386387
static void
387-
postquel_end(execution_state *es, SQLFunctionCachePtr fcache)
388+
postquel_end(execution_state *es)
388389
{
389390
Snapshot saveActiveSnapshot;
390391

@@ -454,10 +455,12 @@ postquel_sub_params(SQLFunctionCachePtr fcache,
454455
static Datum
455456
postquel_execute(execution_state *es,
456457
FunctionCallInfo fcinfo,
457-
SQLFunctionCachePtr fcache)
458+
SQLFunctionCachePtr fcache,
459+
MemoryContext resultcontext)
458460
{
459461
TupleTableSlot *slot;
460462
Datum value;
463+
MemoryContext oldcontext;
461464

462465
if (es->status == F_EXEC_START)
463466
postquel_start(es, fcache);
@@ -470,7 +473,7 @@ postquel_execute(execution_state *es,
470473
* We fall out here for all cases except where we have obtained
471474
* a row from a function's final SELECT.
472475
*/
473-
postquel_end(es, fcache);
476+
postquel_end(es);
474477
fcinfo->isnull = true;
475478
return (Datum) NULL;
476479
}
@@ -482,8 +485,12 @@ postquel_execute(execution_state *es,
482485
Assert(LAST_POSTQUEL_COMMAND(es));
483486

484487
/*
485-
* Set up to return the function value.
488+
* Set up to return the function value. For pass-by-reference
489+
* datatypes, be sure to allocate the result in resultcontext,
490+
* not the current memory context (which has query lifespan).
486491
*/
492+
oldcontext = MemoryContextSwitchTo(resultcontext);
493+
487494
if (fcache->returnsTuple)
488495
{
489496
/*
@@ -492,7 +499,7 @@ postquel_execute(execution_state *es,
492499
* reasons why we do this:
493500
*
494501
* 1. To copy the tuple out of the child execution context and
495-
* into our own context.
502+
* into the desired result context.
496503
*
497504
* 2. To remove any junk attributes present in the raw subselect
498505
* result. (This is probably not absolutely necessary, but it
@@ -553,21 +560,23 @@ postquel_execute(execution_state *es,
553560
{
554561
/*
555562
* Returning a scalar, which we have to extract from the first
556-
* column of the SELECT result, and then copy into current
557-
* execution context if needed.
563+
* column of the SELECT result, and then copy into result
564+
* context if needed.
558565
*/
559566
value = slot_getattr(slot, 1, &(fcinfo->isnull));
560567

561568
if (!fcinfo->isnull)
562569
value = datumCopy(value, fcache->typbyval, fcache->typlen);
563570
}
564571

572+
MemoryContextSwitchTo(oldcontext);
573+
565574
/*
566575
* If this is a single valued function we have to end the function
567576
* execution now.
568577
*/
569578
if (!fcinfo->flinfo->fn_retset)
570-
postquel_end(es, fcache);
579+
postquel_end(es);
571580

572581
return value;
573582
}
@@ -627,7 +636,7 @@ fmgr_sql(PG_FUNCTION_ARGS)
627636
*/
628637
while (es)
629638
{
630-
result = postquel_execute(es, fcinfo, fcache);
639+
result = postquel_execute(es, fcinfo, fcache, oldcontext);
631640
if (es->status != F_EXEC_DONE)
632641
break;
633642
es = es->next;
@@ -824,7 +833,7 @@ ShutdownSQLFunction(Datum arg)
824833
{
825834
/* Shut down anything still running */
826835
if (es->status == F_EXEC_RUN)
827-
postquel_end(es, fcache);
836+
postquel_end(es);
828837
/* Reset states to START in case we're called again */
829838
es->status = F_EXEC_START;
830839
es = es->next;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy