diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2004-04-01 21:28:47 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2004-04-01 21:28:47 +0000 |
commit | 375369acd1c621bdc683c58bc9c31d4e79d14849 (patch) | |
tree | f29974842cea4105c92da6031bac736ddf5f833a /src/backend/executor/functions.c | |
parent | 8590a62b75d3dba24609eb46b34fac13ed881d9e (diff) | |
download | postgresql-375369acd1c621bdc683c58bc9c31d4e79d14849.tar.gz postgresql-375369acd1c621bdc683c58bc9c31d4e79d14849.zip |
Replace TupleTableSlot convention for whole-row variables and function
results with tuples as ordinary varlena Datums. This commit does not
in itself do much for us, except eliminate the horrid memory leak
associated with evaluation of whole-row variables. However, it lays the
groundwork for allowing composite types as table columns, and perhaps
some other useful features as well. Per my proposal of a few days ago.
Diffstat (limited to 'src/backend/executor/functions.c')
-rw-r--r-- | src/backend/executor/functions.c | 124 |
1 files changed, 36 insertions, 88 deletions
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index 8dec6131fb4..aa7652e07ef 100644 --- a/src/backend/executor/functions.c +++ b/src/backend/executor/functions.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.78 2004/03/21 22:29:11 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.79 2004/04/01 21:28:44 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -24,8 +24,10 @@ #include "tcop/tcopprot.h" #include "tcop/utility.h" #include "utils/builtins.h" +#include "utils/datum.h" #include "utils/lsyscache.h" #include "utils/syscache.h" +#include "utils/typcache.h" /* @@ -61,10 +63,6 @@ typedef struct bool returnsTuple; /* true if return type is a tuple */ bool shutdown_reg; /* true if registered shutdown callback */ - TupleTableSlot *funcSlot; /* if one result we need to copy it before - * we end execution of the function and - * free stuff */ - ParamListInfo paramLI; /* Param list representing current args */ /* head of linked list of execution_state records */ @@ -196,34 +194,9 @@ init_sql_fcache(FmgrInfo *finfo) * get the type length and by-value flag from the type tuple */ fcache->typlen = typeStruct->typlen; - - if (typeStruct->typtype != 'c' && rettype != RECORDOID) - { - /* The return type is not a composite type, so just use byval */ - fcache->typbyval = typeStruct->typbyval; - fcache->returnsTuple = false; - } - else - { - /* - * This is a hack. We assume here that any function returning a - * tuple returns it by reference. This needs to be fixed, since - * actually the mechanism isn't quite like return-by-reference. - */ - fcache->typbyval = false; - fcache->returnsTuple = true; - } - - /* - * If we are returning exactly one result then we have to copy tuples - * and by reference results because we have to end the execution - * before we return the results. When you do this everything - * allocated by the executor (i.e. slots and tuples) is freed. - */ - if (!finfo->fn_retset && !fcache->typbyval) - fcache->funcSlot = MakeTupleTableSlot(); - else - fcache->funcSlot = NULL; + fcache->typbyval = typeStruct->typbyval; + fcache->returnsTuple = (typeStruct->typtype == 'c' || + rettype == RECORDOID); /* * Parse and plan the queries. We need the argument type info to pass @@ -366,39 +339,6 @@ postquel_sub_params(SQLFunctionCachePtr fcache, fcache->paramLI = paramLI; } -static TupleTableSlot * -copy_function_result(SQLFunctionCachePtr fcache, - TupleTableSlot *resultSlot) -{ - TupleTableSlot *funcSlot; - TupleDesc resultTd; - HeapTuple resultTuple; - HeapTuple newTuple; - - Assert(!TupIsNull(resultSlot)); - resultTuple = resultSlot->val; - - funcSlot = fcache->funcSlot; - - if (funcSlot == NULL) - return resultSlot; /* no need to copy result */ - - /* - * If first time through, we have to initialize the funcSlot's tuple - * descriptor. - */ - if (funcSlot->ttc_tupleDescriptor == NULL) - { - resultTd = CreateTupleDescCopy(resultSlot->ttc_tupleDescriptor); - ExecSetSlotDescriptor(funcSlot, resultTd, true); - ExecSetSlotDescriptorIsNew(funcSlot, true); - } - - newTuple = heap_copytuple(resultTuple); - - return ExecStoreTuple(newTuple, funcSlot, InvalidBuffer, true); -} - static Datum postquel_execute(execution_state *es, FunctionCallInfo fcinfo, @@ -429,43 +369,51 @@ postquel_execute(execution_state *es, if (LAST_POSTQUEL_COMMAND(es)) { - TupleTableSlot *resSlot; - /* - * Copy the result. copy_function_result is smart enough to do - * nothing when no action is called for. This helps reduce the - * logic and code redundancy here. + * Set up to return the function value. */ - resSlot = copy_function_result(fcache, slot); + HeapTuple tup = slot->val; + TupleDesc tupDesc = slot->ttc_tupleDescriptor; - /* - * If we are supposed to return a tuple, we return the tuple slot - * pointer converted to Datum. If we are supposed to return a - * simple value, then project out the first attribute of the - * result tuple (ie, take the first result column of the final - * SELECT). - */ if (fcache->returnsTuple) { /* + * We are returning the whole tuple, so copy it into current + * execution context and make sure it is a valid Datum. + * * XXX do we need to remove junk attrs from the result tuple? * Probably OK to leave them, as long as they are at the end. */ - value = PointerGetDatum(resSlot); + HeapTupleHeader dtup; + + dtup = (HeapTupleHeader) palloc(tup->t_len); + memcpy((char *) dtup, (char *) tup->t_data, tup->t_len); + + /* + * For RECORD results, make sure a typmod has been assigned. + */ + if (tupDesc->tdtypeid == RECORDOID && + tupDesc->tdtypmod < 0) + assign_record_type_typmod(tupDesc); + + HeapTupleHeaderSetDatumLength(dtup, tup->t_len); + HeapTupleHeaderSetTypeId(dtup, tupDesc->tdtypeid); + HeapTupleHeaderSetTypMod(dtup, tupDesc->tdtypmod); + + value = PointerGetDatum(dtup); fcinfo->isnull = false; } else { - value = heap_getattr(resSlot->val, - 1, - resSlot->ttc_tupleDescriptor, - &(fcinfo->isnull)); - /* - * Note: if result type is pass-by-reference then we are - * returning a pointer into the tuple copied by - * copy_function_result. This is OK. + * 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. */ + value = heap_getattr(tup, 1, tupDesc, &(fcinfo->isnull)); + + if (!fcinfo->isnull) + value = datumCopy(value, fcache->typbyval, fcache->typlen); } /* |