On Tue, 2008-02-26 at 00:17 -0800, Neil Conway wrote:
> You didn't comment on my proposed solution (FreeTupleDesc() iff refcount
> == -1).

Attached is a revised version of this patch. It makes the
FreeTupleDesc() change described above, and fixes a bug: in
SRF_RETURN_DONE(), we need to be sure to switch back to the caller's
context before deleting the multi_call_ctx, since some SRFs (e.g.
dblink) call SRF_RETURN_DONE() while still inside the multi_call_ctx.

I'd like to apply this change to back branches reasonably soon, so if
you have a better way to do the FreeTupleDesc() hack, let me know.

-Neil

Index: src/backend/executor/nodeFunctionscan.c
===================================================================
RCS file: /home/neilc/postgres/cvs_root/pgsql/src/backend/executor/nodeFunctionscan.c,v
retrieving revision 1.45
diff -p -c -r1.45 nodeFunctionscan.c
*** src/backend/executor/nodeFunctionscan.c	1 Jan 2008 19:45:49 -0000	1.45
--- src/backend/executor/nodeFunctionscan.c	26 Feb 2008 19:04:49 -0000
*************** FunctionNext(FunctionScanState *node)
*** 77,83 ****
--- 77,93 ----
  		 * do it always.
  		 */
  		if (funcTupdesc)
+ 		{
  			tupledesc_match(node->tupdesc, funcTupdesc);
+ 
+ 			/*
+ 			 * If it is a dynamically-allocated TupleDesc, free it: it is
+ 			 * typically allocated in the EState's per-query context, so we
+ 			 * must avoid leaking it on rescan.
+ 			 */
+ 			if (funcTupdesc->tdrefcount == -1)
+ 				FreeTupleDesc(funcTupdesc);
+ 		}
  	}
  
  	/*
Index: src/backend/utils/fmgr/funcapi.c
===================================================================
RCS file: /home/neilc/postgres/cvs_root/pgsql/src/backend/utils/fmgr/funcapi.c,v
retrieving revision 1.37
diff -p -c -r1.37 funcapi.c
*** src/backend/utils/fmgr/funcapi.c	1 Jan 2008 19:45:53 -0000	1.37
--- src/backend/utils/fmgr/funcapi.c	26 Feb 2008 19:32:47 -0000
***************
*** 23,28 ****
--- 23,29 ----
  #include "utils/array.h"
  #include "utils/builtins.h"
  #include "utils/lsyscache.h"
+ #include "utils/memutils.h"
  #include "utils/syscache.h"
  #include "utils/typcache.h"
  
*************** init_MultiFuncCall(PG_FUNCTION_ARGS)
*** 63,75 ****
  		/*
  		 * First call
  		 */
! 		ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
  
  		/*
  		 * Allocate suitably long-lived space and zero it
  		 */
  		retval = (FuncCallContext *)
! 			MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt,
  								   sizeof(FuncCallContext));
  
  		/*
--- 64,86 ----
  		/*
  		 * First call
  		 */
! 		ReturnSetInfo  *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
! 		MemoryContext	multi_call_ctx;
! 
! 		/*
! 		 * Create a suitably long-lived context to hold cross-call data
! 		 */
! 		multi_call_ctx = AllocSetContextCreate(fcinfo->flinfo->fn_mcxt,
! 											   "SRF multi-call context",
! 											   ALLOCSET_SMALL_MINSIZE,
! 											   ALLOCSET_SMALL_INITSIZE,
! 											   ALLOCSET_SMALL_MAXSIZE);
  
  		/*
  		 * Allocate suitably long-lived space and zero it
  		 */
  		retval = (FuncCallContext *)
! 			MemoryContextAllocZero(multi_call_ctx,
  								   sizeof(FuncCallContext));
  
  		/*
*************** init_MultiFuncCall(PG_FUNCTION_ARGS)
*** 81,87 ****
  		retval->user_fctx = NULL;
  		retval->attinmeta = NULL;
  		retval->tuple_desc = NULL;
! 		retval->multi_call_memory_ctx = fcinfo->flinfo->fn_mcxt;
  
  		/*
  		 * save the pointer for cross-call use
--- 92,98 ----
  		retval->user_fctx = NULL;
  		retval->attinmeta = NULL;
  		retval->tuple_desc = NULL;
! 		retval->multi_call_memory_ctx = multi_call_ctx;
  
  		/*
  		 * save the pointer for cross-call use
*************** shutdown_MultiFuncCall(Datum arg)
*** 168,180 ****
  	flinfo->fn_extra = NULL;
  
  	/*
! 	 * Caller is responsible to free up memory for individual struct elements
! 	 * other than att_in_funcinfo and elements.
  	 */
! 	if (funcctx->attinmeta != NULL)
! 		pfree(funcctx->attinmeta);
! 
! 	pfree(funcctx);
  }
  
  
--- 179,189 ----
  	flinfo->fn_extra = NULL;
  
  	/*
! 	 * Delete context that holds all multi-call data, including the
! 	 * FuncCallContext itself
  	 */
! 	MemoryContextSwitchTo(flinfo->fn_mcxt);
! 	MemoryContextDelete(funcctx->multi_call_memory_ctx);
  }
  
  
---------------------------(end of broadcast)---------------------------
TIP 1: if posting/reading through Usenet, please send an appropriate
       subscribe-nomail command to [EMAIL PROTECTED] so that your
       message can get through to the mailing list cleanly

Reply via email to