mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
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.
This commit is contained in:
@ -1,6 +1,6 @@
|
||||
<!--
|
||||
Documentation of the system catalogs, directed toward PostgreSQL developers
|
||||
$PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.84 2004/02/15 21:01:38 tgl Exp $
|
||||
$PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.85 2004/04/01 21:28:43 tgl Exp $
|
||||
-->
|
||||
|
||||
<chapter id="catalogs">
|
||||
@ -809,24 +809,6 @@
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><structfield>attisset</structfield></entry>
|
||||
<entry><type>bool</type></entry>
|
||||
<entry></entry>
|
||||
<entry>
|
||||
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
|
||||
<structname>pg_proc</structname> catalog. The
|
||||
<structname>pg_proc</structname> row contains the query
|
||||
string that defines this set, i.e., the query to run to get
|
||||
the set. So the <structfield>atttypid</structfield> (see
|
||||
above) refers to the type returned by this query, but the
|
||||
actual length of this attribute is the length (size) of an
|
||||
<type>oid</type>. --- At least this is the theory. All this
|
||||
is probably quite broken these days.
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><structfield>attalign</structfield></entry>
|
||||
<entry><type>char</type></entry>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!--
|
||||
$PostgreSQL: pgsql/doc/src/sgml/spi.sgml,v 1.33 2004/03/17 01:05:10 momjian Exp $
|
||||
$PostgreSQL: pgsql/doc/src/sgml/spi.sgml,v 1.34 2004/04/01 21:28:43 tgl Exp $
|
||||
-->
|
||||
|
||||
<chapter id="spi">
|
||||
@ -1953,8 +1953,7 @@ char * SPI_getrelname(Relation <parameter>rel</parameter>)
|
||||
allocations made by <function>palloc</function>,
|
||||
<function>repalloc</function>, or SPI utility functions (except for
|
||||
<function>SPI_copytuple</function>,
|
||||
<function>SPI_copytupledesc</function>,
|
||||
<function>SPI_copytupleintoslot</function>,
|
||||
<function>SPI_returntuple</function>,
|
||||
<function>SPI_modifytuple</function>, and
|
||||
<function>SPI_palloc</function>) are made in this context. When a
|
||||
procedure disconnects from the SPI manager (via
|
||||
@ -2169,7 +2168,9 @@ HeapTuple SPI_copytuple(HeapTuple <parameter>row</parameter>)
|
||||
|
||||
<para>
|
||||
<function>SPI_copytuple</function> 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 <function>SPI_returntuple</function> instead.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
@ -2200,21 +2201,21 @@ HeapTuple SPI_copytuple(HeapTuple <parameter>row</parameter>)
|
||||
|
||||
<!-- *********************************************** -->
|
||||
|
||||
<refentry id="spi-spi-copytupledesc">
|
||||
<refentry id="spi-spi-returntuple">
|
||||
<refmeta>
|
||||
<refentrytitle>SPI_copytupledesc</refentrytitle>
|
||||
<refentrytitle>SPI_returntuple</refentrytitle>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>SPI_copytupledesc</refname>
|
||||
<refpurpose>make a copy of a row descriptor in the upper executor context</refpurpose>
|
||||
<refname>SPI_returntuple</refname>
|
||||
<refpurpose>prepare to return a tuple as a Datum</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<indexterm><primary>SPI_copytupledesc</primary></indexterm>
|
||||
<indexterm><primary>SPI_returntuple</primary></indexterm>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<synopsis>
|
||||
TupleDesc SPI_copytupledesc(TupleDesc <parameter>tupdesc</parameter>)
|
||||
HeapTupleHeader SPI_returntuple(HeapTuple <parameter>row</parameter>, TupleDesc <parameter>rowdesc</parameter>)
|
||||
</synopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
@ -2222,63 +2223,16 @@ TupleDesc SPI_copytupledesc(TupleDesc <parameter>tupdesc</parameter>)
|
||||
<title>Description</title>
|
||||
|
||||
<para>
|
||||
<function>SPI_copytupledesc</function> makes a copy of a row
|
||||
descriptor in the upper executor context.
|
||||
<function>SPI_returntuple</function> 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.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Arguments</title>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><literal>TupleDesc <parameter>tupdesc</parameter></literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
row descriptor to be copied
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Return Value</title>
|
||||
|
||||
<para>
|
||||
the copied row descriptor; <symbol>NULL</symbol> only if
|
||||
<parameter>tupdesc</parameter> is <symbol>NULL</symbol>
|
||||
</para>
|
||||
</refsect1>
|
||||
</refentry>
|
||||
|
||||
<!-- *********************************************** -->
|
||||
|
||||
<refentry id="spi-spi-copytupleintoslot">
|
||||
<refmeta>
|
||||
<refentrytitle>SPI_copytupleintoslot</refentrytitle>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>SPI_copytupleintoslot</refname>
|
||||
<refpurpose>make a copy of a row and descriptor in the upper executor context</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<indexterm><primary>SPI_copytupleintoslot</primary></indexterm>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<synopsis>
|
||||
TupleTableSlot * SPI_copytupleintoslot(HeapTuple <parameter>row</parameter>, TupleDesc <parameter>rowdesc</parameter>)
|
||||
</synopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para>
|
||||
<function>SPI_copytupleintoslot</function> makes a copy of a row in
|
||||
the upper executor context, returning it in the form of a filled-in
|
||||
<type>TupleTableSlot</type> structure.
|
||||
Note that this should be used for functions that are declared to return
|
||||
composite types. It is not used for triggers; use
|
||||
<function>SPI_copytuple</> for returning a modified row in a trigger.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
@ -2299,7 +2253,8 @@ TupleTableSlot * SPI_copytupleintoslot(HeapTuple <parameter>row</parameter>, Tup
|
||||
<term><literal>TupleDesc <parameter>rowdesc</parameter></literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
row descriptor to be copied
|
||||
descriptor for row (pass the same descriptor each time for most
|
||||
effective caching)
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@ -2310,9 +2265,9 @@ TupleTableSlot * SPI_copytupleintoslot(HeapTuple <parameter>row</parameter>, Tup
|
||||
<title>Return Value</title>
|
||||
|
||||
<para>
|
||||
<type>TupleTableSlot</type> containing the copied row and
|
||||
descriptor; <symbol>NULL</symbol> only if
|
||||
<parameter>row</parameter> or <parameter>rowdesc</parameter> are
|
||||
<type>HeapTupleHeader</type> pointing to copied row;
|
||||
<symbol>NULL</symbol> only if
|
||||
<parameter>row</parameter> or <parameter>rowdesc</parameter> is
|
||||
<symbol>NULL</symbol>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!--
|
||||
$PostgreSQL: pgsql/doc/src/sgml/xfunc.sgml,v 1.80 2004/03/09 16:57:47 neilc Exp $
|
||||
$PostgreSQL: pgsql/doc/src/sgml/xfunc.sgml,v 1.81 2004/04/01 21:28:43 tgl Exp $
|
||||
-->
|
||||
|
||||
<sect1 id="xfunc">
|
||||
@ -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)
|
||||
<function>GetAttributeByName</function> is the
|
||||
<productname>PostgreSQL</productname> system function that
|
||||
returns attributes out of the specified row. It has
|
||||
three arguments: the argument of type <type>TupleTableSlot*</type> passed into
|
||||
three arguments: the argument of type <type>HeapTupleHeader</type> passed
|
||||
into
|
||||
the function, the name of the desired attribute, and a
|
||||
return parameter that tells whether the attribute
|
||||
is null. <function>GetAttributeByName</function> returns a <type>Datum</type>
|
||||
@ -1674,6 +1675,11 @@ c_overpaid(PG_FUNCTION_ARGS)
|
||||
appropriate <function>DatumGet<replaceable>XXX</replaceable>()</function> macro.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
There is also <function>GetAttributeByNum</function>, which selects
|
||||
the target attribute by column number instead of name.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The following command declares the function
|
||||
<function>c_overpaid</function> in SQL:
|
||||
@ -1681,8 +1687,11 @@ c_overpaid(PG_FUNCTION_ARGS)
|
||||
<programlisting>
|
||||
CREATE FUNCTION c_overpaid(emp, integer) RETURNS boolean
|
||||
AS '<replaceable>DIRECTORY</replaceable>/funcs', 'c_overpaid'
|
||||
LANGUAGE C;
|
||||
LANGUAGE C STRICT;
|
||||
</programlisting>
|
||||
|
||||
Notice we have used <literal>STRICT</> so that we did not have to
|
||||
check whether the input arguments were NULL.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
@ -1700,38 +1709,25 @@ CREATE FUNCTION c_overpaid(emp, integer) RETURNS boolean
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The support for returning composite data types (or rows) starts
|
||||
with the <structname>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 <structname>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 <structname>AttInMetadata</>
|
||||
structure should be computed once during the first call and saved
|
||||
for reuse in later calls. <structname>AttInMetadata</> also
|
||||
saves a pointer to the original <structname>TupleDesc</>.
|
||||
<programlisting>
|
||||
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;
|
||||
</programlisting>
|
||||
There are two ways you can build a composite data value (henceforth
|
||||
a <quote>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 <structname>TupleDesc</>
|
||||
descriptor for the tuple structure. When working with Datums, you
|
||||
pass the <structname>TupleDesc</> to <function>BlessTupleDesc</>,
|
||||
and then call <function>heap_formtuple</> for each row. When working
|
||||
with C strings, you pass the <structname>TupleDesc</> to
|
||||
<function>TupleDescGetAttInMetadata</>, and then call
|
||||
<function>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.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
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
|
||||
<structname>TupleDesc</>. If you want to use a named composite type,
|
||||
you can fetch the information from the system catalogs. Use
|
||||
<programlisting>
|
||||
TupleDesc RelationNameGetTupleDesc(const char *relname)
|
||||
</programlisting>
|
||||
@ -1741,36 +1737,43 @@ TupleDesc TypeGetTupleDesc(Oid typeoid, List *colaliases)
|
||||
</programlisting>
|
||||
to get a <structname>TupleDesc</> based on a type OID. This can
|
||||
be used to get a <structname>TupleDesc</> for a base or
|
||||
composite type. Then
|
||||
composite type. When writing a function that returns
|
||||
<structname>record</>, the expected <structname>TupleDesc</>
|
||||
must be passed in by the caller.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Once you have a <structname>TupleDesc</>, call
|
||||
<programlisting>
|
||||
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
|
||||
</programlisting>
|
||||
if you plan to work with Datums, or
|
||||
<programlisting>
|
||||
AttInMetadata *TupleDescGetAttInMetadata(TupleDesc tupdesc)
|
||||
</programlisting>
|
||||
will return a pointer to an <structname>AttInMetadata</>,
|
||||
initialized based on the given
|
||||
<structname>TupleDesc</>. <structname>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
|
||||
<structname>FuncCallContext</> structure --- use the
|
||||
<structfield>tuple_desc</> or <structfield>attinmeta</> field
|
||||
respectively.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
To return a tuple you must create a tuple slot based on the
|
||||
<structname>TupleDesc</>. You can use
|
||||
When working with Datums, use
|
||||
<programlisting>
|
||||
TupleTableSlot *TupleDescGetSlot(TupleDesc tupdesc)
|
||||
HeapTuple heap_formtuple(TupleDesc tupdesc, Datum *values, char *nulls)
|
||||
</programlisting>
|
||||
to initialize this tuple slot, or obtain one through other (user provided)
|
||||
means. The tuple slot is needed to create a <type>Datum</> for return by the
|
||||
function. The same slot can (and should) be reused on each call.
|
||||
to build a <structname>HeapTuple</> given user data in Datum form.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
After constructing an <structname>AttInMetadata</> structure,
|
||||
When working with C strings, use
|
||||
<programlisting>
|
||||
HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
|
||||
</programlisting>
|
||||
can be used to build a <structname>HeapTuple</> given user data
|
||||
in C string form. <literal>values</literal> is an array of C strings, one for
|
||||
each attribute of the return row. Each C string should be in
|
||||
to build a <structname>HeapTuple</> given user data
|
||||
in C string form. <literal>values</literal> 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 <parameter>values</> array
|
||||
@ -1778,25 +1781,13 @@ HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
|
||||
be called again for each row you return.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Building a tuple via <function>TupleDescGetAttInMetadata</> and
|
||||
<function>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
|
||||
<type>Datum</> values, you should instead use the underlying
|
||||
function <function>heap_formtuple</> to convert the
|
||||
<type>Datum</type> values directly into a tuple. You will still need
|
||||
the <structname>TupleDesc</> and a <structname>TupleTableSlot</>,
|
||||
but not <structname>AttInMetadata</>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Once you have built a tuple to return from your function, it
|
||||
must be converted into a <type>Datum</>. Use
|
||||
<programlisting>
|
||||
TupleGetDatum(TupleTableSlot *slot, HeapTuple tuple)
|
||||
HeapTupleGetDatum(HeapTuple tuple)
|
||||
</programlisting>
|
||||
to get a <type>Datum</> given a tuple and a slot. This
|
||||
to convert a <structname>HeapTuple</> into a valid Datum. This
|
||||
<type>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;
|
||||
</programlisting>
|
||||
</para>
|
||||
@ -1956,8 +1959,6 @@ my_set_returning_function(PG_FUNCTION_ARGS)
|
||||
<replaceable>user code</replaceable>
|
||||
<replaceable>if returning composite</replaceable>
|
||||
<replaceable>build TupleDesc, and perhaps AttInMetadata</replaceable>
|
||||
<replaceable>obtain slot</replaceable>
|
||||
funcctx->slot = slot;
|
||||
<replaceable>endif returning composite</replaceable>
|
||||
<replaceable>user code</replaceable>
|
||||
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]);
|
||||
|
Reference in New Issue
Block a user