From 375369acd1c621bdc683c58bc9c31d4e79d14849 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Thu, 1 Apr 2004 21:28:47 +0000 Subject: 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. --- doc/src/sgml/catalogs.sgml | 20 +----- doc/src/sgml/spi.sgml | 91 +++++++------------------- doc/src/sgml/xfunc.sgml | 155 ++++++++++++++++++++++----------------------- 3 files changed, 98 insertions(+), 168 deletions(-) (limited to 'doc/src') diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index 196fdc6efdd..0cdbdcfb7b5 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -1,6 +1,6 @@ @@ -809,24 +809,6 @@ - - attisset - bool - - - If true, this attribute is a set. In that case, what is really - stored in the attribute is the OID of a row in the - pg_proc catalog. The - pg_proc row contains the query - string that defines this set, i.e., the query to run to get - the set. So the atttypid (see - above) refers to the type returned by this query, but the - actual length of this attribute is the length (size) of an - oid. --- At least this is the theory. All this - is probably quite broken these days. - - - attalign char diff --git a/doc/src/sgml/spi.sgml b/doc/src/sgml/spi.sgml index c87a136bdd4..4018c2e3e1b 100644 --- a/doc/src/sgml/spi.sgml +++ b/doc/src/sgml/spi.sgml @@ -1,5 +1,5 @@ @@ -1953,8 +1953,7 @@ char * SPI_getrelname(Relation rel) allocations made by palloc, repalloc, or SPI utility functions (except for SPI_copytuple, - SPI_copytupledesc, - SPI_copytupleintoslot, + SPI_returntuple, SPI_modifytuple, and SPI_palloc) are made in this context. When a procedure disconnects from the SPI manager (via @@ -2169,7 +2168,9 @@ HeapTuple SPI_copytuple(HeapTuple row) SPI_copytuple makes a copy of a row in the - upper executor context. + upper executor context. This is normally used to return a modified + row from a trigger. In a function declared to return a composite + type, use SPI_returntuple instead. @@ -2200,21 +2201,21 @@ HeapTuple SPI_copytuple(HeapTuple row) - + - SPI_copytupledesc + SPI_returntuple - SPI_copytupledesc - make a copy of a row descriptor in the upper executor context + SPI_returntuple + prepare to return a tuple as a Datum - SPI_copytupledesc + SPI_returntuple -TupleDesc SPI_copytupledesc(TupleDesc tupdesc) +HeapTupleHeader SPI_returntuple(HeapTuple row, TupleDesc rowdesc) @@ -2222,63 +2223,16 @@ TupleDesc SPI_copytupledesc(TupleDesc tupdesc) Description - SPI_copytupledesc makes a copy of a row - descriptor in the upper executor context. + SPI_returntuple makes a copy of a row in + the upper executor context, returning it in the form of a rowtype Datum. + The returned pointer need only be converted to Datum via PointerGetDatum + before returning. - - - - Arguments - - - - TupleDesc tupdesc - - - row descriptor to be copied - - - - - - - - Return Value - - - the copied row descriptor; NULL only if - tupdesc is NULL - - - - - - - - - SPI_copytupleintoslot - - - - SPI_copytupleintoslot - make a copy of a row and descriptor in the upper executor context - - - SPI_copytupleintoslot - - - -TupleTableSlot * SPI_copytupleintoslot(HeapTuple row, TupleDesc rowdesc) - - - - - Description - SPI_copytupleintoslot makes a copy of a row in - the upper executor context, returning it in the form of a filled-in - TupleTableSlot structure. + Note that this should be used for functions that are declared to return + composite types. It is not used for triggers; use + SPI_copytuple for returning a modified row in a trigger. @@ -2299,7 +2253,8 @@ TupleTableSlot * SPI_copytupleintoslot(HeapTuple row, Tup TupleDesc rowdesc - row descriptor to be copied + descriptor for row (pass the same descriptor each time for most + effective caching) @@ -2310,9 +2265,9 @@ TupleTableSlot * SPI_copytupleintoslot(HeapTuple row, Tup Return Value - TupleTableSlot containing the copied row and - descriptor; NULL only if - row or rowdesc are + HeapTupleHeader pointing to copied row; + NULL only if + row or rowdesc is NULL diff --git a/doc/src/sgml/xfunc.sgml b/doc/src/sgml/xfunc.sgml index c8f71296857..4b06aefd362 100644 --- a/doc/src/sgml/xfunc.sgml +++ b/doc/src/sgml/xfunc.sgml @@ -1,5 +1,5 @@ @@ -1623,7 +1623,7 @@ SELECT name, c_overpaid(emp, 1500) AS overpaid #include "executor/executor.h" /* for GetAttributeByName() */ bool -c_overpaid(TupleTableSlot *t, /* the current row of emp */ +c_overpaid(HeapTupleHeader t, /* the current row of emp */ int32 limit) { bool isnull; @@ -1647,7 +1647,7 @@ PG_FUNCTION_INFO_V1(c_overpaid); Datum c_overpaid(PG_FUNCTION_ARGS) { - TupleTableSlot *t = (TupleTableSlot *) PG_GETARG_POINTER(0); + HeapTupleHeader t = PG_GETARG_HEAPTUPLEHEADER(0); int32 limit = PG_GETARG_INT32(1); bool isnull; int32 salary; @@ -1666,7 +1666,8 @@ c_overpaid(PG_FUNCTION_ARGS) GetAttributeByName is the PostgreSQL system function that returns attributes out of the specified row. It has - three arguments: the argument of type TupleTableSlot* passed into + three arguments: the argument of type HeapTupleHeader passed + into the function, the name of the desired attribute, and a return parameter that tells whether the attribute is null. GetAttributeByName returns a Datum @@ -1674,6 +1675,11 @@ c_overpaid(PG_FUNCTION_ARGS) appropriate DatumGetXXX() macro. + + There is also GetAttributeByNum, which selects + the target attribute by column number instead of name. + + The following command declares the function c_overpaid in SQL: @@ -1681,8 +1687,11 @@ c_overpaid(PG_FUNCTION_ARGS) CREATE FUNCTION c_overpaid(emp, integer) RETURNS boolean AS 'DIRECTORY/funcs', 'c_overpaid' - LANGUAGE C; + LANGUAGE C STRICT; + + Notice we have used STRICT so that we did not have to + check whether the input arguments were NULL. @@ -1700,38 +1709,25 @@ CREATE FUNCTION c_overpaid(emp, integer) RETURNS boolean - The support for returning composite data types (or rows) starts - with the AttInMetadata structure. This structure - holds arrays of individual attribute information needed to create - a row from raw C strings. The information contained in the - structure is derived from a TupleDesc structure, - but it is stored to avoid redundant computations on each call to - a set-returning function (see next section). In the case of a - function returning a set, the AttInMetadata - structure should be computed once during the first call and saved - for reuse in later calls. AttInMetadata also - saves a pointer to the original TupleDesc. - -typedef struct AttInMetadata -{ - /* full TupleDesc */ - TupleDesc tupdesc; - - /* array of attribute type input function finfo */ - FmgrInfo *attinfuncs; - - /* array of attribute type typelem */ - Oid *attelems; - - /* array of attribute typmod */ - int32 *atttypmods; -} AttInMetadata; - + There are two ways you can build a composite data value (henceforth + a tuple): you can build it from an array of Datum values, + or from an array of C strings that can be passed to the input + conversion functions of the tuple's column datatypes. In either + case, you first need to obtain or construct a TupleDesc + descriptor for the tuple structure. When working with Datums, you + pass the TupleDesc to BlessTupleDesc, + and then call heap_formtuple for each row. When working + with C strings, you pass the TupleDesc to + TupleDescGetAttInMetadata, and then call + BuildTupleFromCStrings for each row. In the case of a + function returning a set of tuples, the setup steps can all be done + once during the first call of the function. - To assist you in populating this structure, several functions and a macro - are available. Use + Several helper functions are available for setting up the initial + TupleDesc. If you want to use a named composite type, + you can fetch the information from the system catalogs. Use TupleDesc RelationNameGetTupleDesc(const char *relname) @@ -1741,36 +1737,43 @@ TupleDesc TypeGetTupleDesc(Oid typeoid, List *colaliases) to get a TupleDesc based on a type OID. This can be used to get a TupleDesc for a base or - composite type. Then + composite type. When writing a function that returns + record, the expected TupleDesc + must be passed in by the caller. + + + + Once you have a TupleDesc, call + +TupleDesc BlessTupleDesc(TupleDesc tupdesc) + + if you plan to work with Datums, or AttInMetadata *TupleDescGetAttInMetadata(TupleDesc tupdesc) - will return a pointer to an AttInMetadata, - initialized based on the given - TupleDesc. AttInMetadata can be - used in conjunction with C strings to produce a properly formed - row value (internally called tuple). + if you plan to work with C strings. If you are writing a function + returning set, you can save the results of these functions in the + FuncCallContext structure --- use the + tuple_desc or attinmeta field + respectively. - To return a tuple you must create a tuple slot based on the - TupleDesc. You can use + When working with Datums, use -TupleTableSlot *TupleDescGetSlot(TupleDesc tupdesc) +HeapTuple heap_formtuple(TupleDesc tupdesc, Datum *values, char *nulls) - to initialize this tuple slot, or obtain one through other (user provided) - means. The tuple slot is needed to create a Datum for return by the - function. The same slot can (and should) be reused on each call. + to build a HeapTuple given user data in Datum form. - After constructing an AttInMetadata structure, + When working with C strings, use HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values) - can be used to build a HeapTuple given user data - in C string form. values is an array of C strings, one for - each attribute of the return row. Each C string should be in + to build a HeapTuple given user data + in C string form. values is an array of C strings, + one for each attribute of the return row. Each C string should be in the form expected by the input function of the attribute data type. In order to return a null value for one of the attributes, the corresponding pointer in the values array @@ -1778,25 +1781,13 @@ HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values) be called again for each row you return. - - Building a tuple via TupleDescGetAttInMetadata and - BuildTupleFromCStrings is only convenient if your - function naturally computes the values to be returned as text - strings. If your code naturally computes the values as a set of - Datum values, you should instead use the underlying - function heap_formtuple to convert the - Datum values directly into a tuple. You will still need - the TupleDesc and a TupleTableSlot, - but not AttInMetadata. - - Once you have built a tuple to return from your function, it must be converted into a Datum. Use -TupleGetDatum(TupleTableSlot *slot, HeapTuple tuple) +HeapTupleGetDatum(HeapTuple tuple) - to get a Datum given a tuple and a slot. This + to convert a HeapTuple into a valid Datum. This Datum can be returned directly if you intend to return just a single row, or it can be used as the current return value in a set-returning function. @@ -1851,8 +1842,8 @@ typedef struct /* * OPTIONAL pointer to result slot * - * slot is for use when returning tuples (i.e., composite data types) - * and is not needed when returning base data types. + * This is obsolete and only present for backwards compatibility, viz, + * user-defined SRFs that use the deprecated TupleDescGetSlot(). */ TupleTableSlot *slot; @@ -1868,9 +1859,9 @@ typedef struct * OPTIONAL pointer to struct containing attribute type input metadata * * attinmeta is for use when returning tuples (i.e., composite data types) - * and is not needed when returning base data types. It - * is only needed if you intend to use BuildTupleFromCStrings() to create - * the return tuple. + * and is not used when returning base data types. It is only needed + * if you intend to use BuildTupleFromCStrings() to create the return + * tuple. */ AttInMetadata *attinmeta; @@ -1883,6 +1874,18 @@ typedef struct * of the SRF. */ MemoryContext multi_call_memory_ctx; + + /* + * OPTIONAL pointer to struct containing tuple description + * + * tuple_desc is for use when returning tuples (i.e. composite data types) + * and is only needed if you are going to build the tuples with + * heap_formtuple() rather than with BuildTupleFromCStrings(). Note that + * the TupleDesc pointer stored here should usually have been run through + * BlessTupleDesc() first. + */ + TupleDesc tuple_desc; + } FuncCallContext; @@ -1956,8 +1959,6 @@ my_set_returning_function(PG_FUNCTION_ARGS) user code if returning composite build TupleDesc, and perhaps AttInMetadata - obtain slot - funcctx->slot = slot; endif returning composite user code MemoryContextSwitchTo(oldcontext); @@ -1998,7 +1999,6 @@ testpassbyval(PG_FUNCTION_ARGS) int call_cntr; int max_calls; TupleDesc tupdesc; - TupleTableSlot *slot; AttInMetadata *attinmeta; /* stuff done only on the first call of the function */ @@ -2018,12 +2018,6 @@ testpassbyval(PG_FUNCTION_ARGS) /* Build a tuple description for a __testpassbyval tuple */ tupdesc = RelationNameGetTupleDesc("__testpassbyval"); - /* allocate a slot for a tuple with this tupdesc */ - slot = TupleDescGetSlot(tupdesc); - - /* assign slot to function context */ - funcctx->slot = slot; - /* * generate attribute metadata needed later to produce tuples from raw * C strings @@ -2039,7 +2033,6 @@ testpassbyval(PG_FUNCTION_ARGS) call_cntr = funcctx->call_cntr; max_calls = funcctx->max_calls; - slot = funcctx->slot; attinmeta = funcctx->attinmeta; if (call_cntr < max_calls) /* do when there is more left to send */ @@ -2049,7 +2042,7 @@ testpassbyval(PG_FUNCTION_ARGS) Datum result; /* - * Prepare a values array for storage in our slot. + * Prepare a values array for building the returned tuple. * This should be an array of C strings which will * be processed later by the type input functions. */ @@ -2066,7 +2059,7 @@ testpassbyval(PG_FUNCTION_ARGS) tuple = BuildTupleFromCStrings(attinmeta, values); /* make the tuple into a datum */ - result = TupleGetDatum(slot, tuple); + result = HeapTupleGetDatum(tuple); /* clean up (this is not really necessary) */ pfree(values[0]); -- cgit v1.2.3