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