*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.96 2005/04/06 16:34:04 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.97 2005/04/10 18:04:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
static void init_sql_fcache(FmgrInfo *finfo);
static void postquel_start(execution_state *es, SQLFunctionCachePtr fcache);
static TupleTableSlot *postquel_getnext(execution_state *es);
-static void postquel_end(execution_state *es, SQLFunctionCachePtr fcache);
+static void postquel_end(execution_state *es);
static void postquel_sub_params(SQLFunctionCachePtr fcache,
FunctionCallInfo fcinfo);
static Datum postquel_execute(execution_state *es,
FunctionCallInfo fcinfo,
- SQLFunctionCachePtr fcache);
+ SQLFunctionCachePtr fcache,
+ MemoryContext resultcontext);
static void sql_exec_error_callback(void *arg);
static void ShutdownSQLFunction(Datum arg);
}
static void
-postquel_end(execution_state *es, SQLFunctionCachePtr fcache)
+postquel_end(execution_state *es)
{
Snapshot saveActiveSnapshot;
static Datum
postquel_execute(execution_state *es,
FunctionCallInfo fcinfo,
- SQLFunctionCachePtr fcache)
+ SQLFunctionCachePtr fcache,
+ MemoryContext resultcontext)
{
TupleTableSlot *slot;
Datum value;
+ MemoryContext oldcontext;
if (es->status == F_EXEC_START)
postquel_start(es, fcache);
* We fall out here for all cases except where we have obtained
* a row from a function's final SELECT.
*/
- postquel_end(es, fcache);
+ postquel_end(es);
fcinfo->isnull = true;
return (Datum) NULL;
}
Assert(LAST_POSTQUEL_COMMAND(es));
/*
- * Set up to return the function value.
+ * Set up to return the function value. For pass-by-reference
+ * datatypes, be sure to allocate the result in resultcontext,
+ * not the current memory context (which has query lifespan).
*/
+ oldcontext = MemoryContextSwitchTo(resultcontext);
+
if (fcache->returnsTuple)
{
/*
* reasons why we do this:
*
* 1. To copy the tuple out of the child execution context and
- * into our own context.
+ * into the desired result context.
*
* 2. To remove any junk attributes present in the raw subselect
* result. (This is probably not absolutely necessary, but it
{
/*
* Returning a scalar, which we have to extract from the first
- * column of the SELECT result, and then copy into current
- * execution context if needed.
+ * column of the SELECT result, and then copy into result
+ * context if needed.
*/
value = slot_getattr(slot, 1, &(fcinfo->isnull));
value = datumCopy(value, fcache->typbyval, fcache->typlen);
}
+ MemoryContextSwitchTo(oldcontext);
+
/*
* If this is a single valued function we have to end the function
* execution now.
*/
if (!fcinfo->flinfo->fn_retset)
- postquel_end(es, fcache);
+ postquel_end(es);
return value;
}
*/
while (es)
{
- result = postquel_execute(es, fcinfo, fcache);
+ result = postquel_execute(es, fcinfo, fcache, oldcontext);
if (es->status != F_EXEC_DONE)
break;
es = es->next;
{
/* Shut down anything still running */
if (es->status == F_EXEC_RUN)
- postquel_end(es, fcache);
+ postquel_end(es);
/* Reset states to START in case we're called again */
es->status = F_EXEC_START;
es = es->next;