diff options
| author | Tom Lane <tgl@sss.pgh.pa.us> | 2002-08-29 00:17:06 +0000 |
|---|---|---|
| committer | Tom Lane <tgl@sss.pgh.pa.us> | 2002-08-29 00:17:06 +0000 |
| commit | 64505ed58ba71df3221e2467dc458af2e1912895 (patch) | |
| tree | 3c110a6d9e3badd87d741976871028760b8f55b5 /doc/src | |
| parent | 7483749d8207c0cbcce5ce69161400ace31a6856 (diff) | |
Code review for standalone composite types, query-specified composite
types, SRFs. Not happy with memory management yet, but I'll commit these
other changes.
Diffstat (limited to 'doc/src')
| -rw-r--r-- | doc/src/sgml/ref/create_type.sgml | 37 | ||||
| -rw-r--r-- | doc/src/sgml/ref/select.sgml | 99 | ||||
| -rw-r--r-- | doc/src/sgml/ref/select_into.sgml | 15 | ||||
| -rw-r--r-- | doc/src/sgml/release.sgml | 3 | ||||
| -rw-r--r-- | doc/src/sgml/xfunc.sgml | 469 |
5 files changed, 359 insertions, 264 deletions
diff --git a/doc/src/sgml/ref/create_type.sgml b/doc/src/sgml/ref/create_type.sgml index f100f4d87b5..b2d454f129b 100644 --- a/doc/src/sgml/ref/create_type.sgml +++ b/doc/src/sgml/ref/create_type.sgml @@ -1,5 +1,5 @@ <!-- -$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_type.sgml,v 1.33 2002/08/23 00:33:24 tgl Exp $ +$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_type.sgml,v 1.34 2002/08/29 00:17:01 tgl Exp $ PostgreSQL documentation --> @@ -32,11 +32,7 @@ CREATE TYPE <replaceable class="parameter">typename</replaceable> ( INPUT = <rep ) CREATE TYPE <replaceable class="parameter">typename</replaceable> AS - ( <replaceable class="PARAMETER">column_definition_list</replaceable> ) - -where <replaceable class="PARAMETER">column_definition_list</replaceable> can be: - -( <replaceable class="PARAMETER">column_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [, ... ] ) + ( <replaceable class="PARAMETER">column_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [, ... ] ) </synopsis> <refsect2 id="R2-SQL-CREATETYPE-1"> @@ -216,8 +212,12 @@ CREATE TYPE type names also must not conflict with table names in the same schema.) </para> + <refsect2> + <title>Base Types</title> + <para> - The first form of <command>CREATE TYPE</command> requires the + The first form of <command>CREATE TYPE</command> creates a new base type + (scalar type). It requires the registration of two functions (using CREATE FUNCTION) before defining the type. The representation of a new base type is determined by <replaceable class="parameter">input_function</replaceable>, which @@ -338,20 +338,27 @@ CREATE TYPE a row fit, but they will be kept in the main table preferentially over <literal>extended</literal> and <literal>external</literal> items.) </para> + </refsect2> + + <refsect2> + <title>Composite Types</title> <para> - The second form of <command>CREATE TYPE</command> requires a column - definition list in the form ( <replaceable class="PARAMETER">column_name</replaceable> - <replaceable class="PARAMETER">data_type</replaceable> [, ... ] ). This - creates a composite type, similar to that of a TABLE or VIEW relation. - A stand-alone composite type is useful as the return type of FUNCTION. + The second form of <command>CREATE TYPE</command> + creates a composite type. + The composite type is specified by a list of column names and datatypes. + This is essentially the same as the row type + of a table, but using <command>CREATE TYPE</command> avoids the need to + create an actual table when all that is wanted is to define a type. + A stand-alone composite type is useful as the return type of a function. </para> + </refsect2> <refsect2> <title>Array Types</title> <para> - Whenever a user-defined data type is created, + Whenever a user-defined base data type is created, <productname>PostgreSQL</productname> automatically creates an associated array type, whose name consists of the base type's name prepended with an underscore. The parser understands this @@ -436,8 +443,8 @@ CREATE TABLE big_objs (id int4, obj bigobj); This example creates a composite type and uses it in a table function definition: <programlisting> -CREATE TYPE compfoo AS (f1 int, f2 int); -CREATE FUNCTION getfoo() RETURNS SETOF compfoo AS 'SELECT fooid, foorefid FROM foo' LANGUAGE SQL; +CREATE TYPE compfoo AS (f1 int, f2 text); +CREATE FUNCTION getfoo() RETURNS SETOF compfoo AS 'SELECT fooid, fooname FROM foo' LANGUAGE SQL; </programlisting> </para> </refsect1> diff --git a/doc/src/sgml/ref/select.sgml b/doc/src/sgml/ref/select.sgml index 5fdaf90f0ac..f6dd0397570 100644 --- a/doc/src/sgml/ref/select.sgml +++ b/doc/src/sgml/ref/select.sgml @@ -1,5 +1,5 @@ <!-- -$Header: /cvsroot/pgsql/doc/src/sgml/ref/select.sgml,v 1.57 2002/08/28 14:35:37 momjian Exp $ +$Header: /cvsroot/pgsql/doc/src/sgml/ref/select.sgml,v 1.58 2002/08/29 00:17:01 tgl Exp $ PostgreSQL documentation --> @@ -40,10 +40,10 @@ where <replaceable class="PARAMETER">from_item</replaceable> can be: ( <replaceable class="PARAMETER">select</replaceable> ) [ AS ] <replaceable class="PARAMETER">alias</replaceable> [ ( <replaceable class="PARAMETER">column_alias_list</replaceable> ) ] | -<replaceable class="PARAMETER">table_function_name</replaceable> ( [ <replaceable class="parameter">argtype</replaceable> [, ...] ] ) +<replaceable class="PARAMETER">table_function_name</replaceable> ( [ <replaceable class="parameter">argument</replaceable> [, ...] ] ) [ AS ] <replaceable class="PARAMETER">alias</replaceable> [ ( <replaceable class="PARAMETER">column_alias_list</replaceable> | <replaceable class="PARAMETER">column_definition_list</replaceable> ) ] | -<replaceable class="PARAMETER">table_function_name</replaceable> ( [ <replaceable class="parameter">argtype</replaceable> [, ...] ] ) +<replaceable class="PARAMETER">table_function_name</replaceable> ( [ <replaceable class="parameter">argument</replaceable> [, ...] ] ) AS ( <replaceable class="PARAMETER">column_definition_list</replaceable> ) | <replaceable class="PARAMETER">from_item</replaceable> [ NATURAL ] <replaceable class="PARAMETER">join_type</replaceable> <replaceable class="PARAMETER">from_item</replaceable> @@ -142,10 +142,14 @@ where <replaceable class="PARAMETER">from_item</replaceable> can be: <term><replaceable class="PARAMETER">alias</replaceable></term> <listitem> <para> - A substitute name for the preceding - <replaceable class="PARAMETER">table_name</replaceable>. + A substitute name for the FROM item containing the alias. An alias is used for brevity or to eliminate ambiguity for self-joins - (where the same table is scanned multiple times). If an alias is + (where the same table is scanned multiple times). When an alias + is provided, it completely hides the actual name of the table or + table function; for example given <literal>FROM foo AS f</>, the + remainder of the SELECT must refer to this FROM item as <literal>f</> + not <literal>foo</>. + If an alias is written, a column alias list can also be written to provide substitute names for one or more columns of the table. </para> @@ -172,12 +176,15 @@ where <replaceable class="PARAMETER">from_item</replaceable> can be: A table function can appear in the FROM clause. This acts as though its output were created as a temporary table for the duration of this single SELECT command. An alias may also be used. If an alias is - written, a column alias list can also be written to provide substitute names - for one or more columns of the table function. If the table function has been - defined as returning the RECORD data type, an alias, or the keyword AS, must - also be present, followed by a column definition list in the form - ( <replaceable class="PARAMETER">column_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [, ... ] ). - The column definition list must match the actual number and types returned by the function. + written, a column alias list can also be written to provide substitute + names for one or more columns of the table function. If the table + function has been defined as returning the <type>record</> data type, + an alias, or the keyword <literal>AS</>, must be present, followed by + a column definition list in the form ( <replaceable + class="PARAMETER">column_name</replaceable> <replaceable + class="PARAMETER">data_type</replaceable> [, ... ] ). + The column definition list must match the actual number and types + of columns returned by the function. </para> </listitem> </varlistentry> @@ -395,7 +402,7 @@ where <replaceable class="PARAMETER">from_item</replaceable> can be: this was the default result, and adding sub-tables was done by appending <command>*</command> to the table name. This old behavior is available via the command - <command>SET SQL_Inheritance TO OFF;</command> + <command>SET SQL_Inheritance TO OFF</command>. </para> <para> @@ -406,16 +413,22 @@ where <replaceable class="PARAMETER">from_item</replaceable> can be: </para> <para> - A FROM item can be a table function (i.e. a function that returns - multiple rows and columns). When a table function is created, it may - be defined to return a named scalar or composite data type (an existing - scalar data type, or a table or view name), or it may be defined to return - a RECORD data type. When a table function is defined to return RECORD, it - must be followed in the FROM clause by an alias, or the keyword AS alone, - and then by a parenthesized list of column names and types. This provides - a query-time composite type definition. The FROM clause composite type - must match the actual composite type returned from the function or an - ERROR will be generated. + A FROM item can be a table function (typically, a function that returns + multiple rows and/or columns, though actually any function can be used). + The function is invoked with the given argument value(s), and then its + output is scanned as though it were a table. + </para> + + <para> + In some cases it is useful to define table functions that can return + different column sets depending on how they are invoked. To support this, + the table function can be declared as returning the pseudo-type + <type>record</>. When such a function is used in FROM, it must be + followed by an alias, or the keyword <literal>AS</> alone, + and then by a parenthesized list of column names and types. This provides + a query-time composite type definition. The composite type definition + must match the actual composite type returned from the function, or an + error will be reported at run-time. </para> <para> @@ -827,6 +840,38 @@ SELECT name FROM distributors ORDER BY code; unless ORDER BY is used to constrain the order. </para> </refsect2> + + <refsect2 id="SQL-FOR-UPDATE"> + <refsect2info> + <date>2002-08-28</date> + </refsect2info> + <title id="sql-for-update-title"> + FOR UPDATE Clause + </title> + <para> + <synopsis> + FOR UPDATE [ OF <replaceable class="PARAMETER">tablename</replaceable> [, ...] ] + </synopsis> + </para> + + <para> + FOR UPDATE causes the rows retrieved by the query to be locked as though + for update. This prevents them from being modified or deleted by other + transactions until the current transaction ends. + </para> + + <para> + If specific tables are named in FOR UPDATE, then only rows coming from + those tables are locked. + </para> + + <para> + FOR UPDATE cannot be used in contexts where returned rows can't be clearly + identified with individual table rows; for example it can't be used with + aggregation. + </para> + </refsect2> + </refsect1> <refsect1 id="R1-SQL-SELECT-2"> @@ -1019,8 +1064,7 @@ SELECT * FROM distributors_2(111) AS (f1 int, f2 text); <productname>PostgreSQL</productname> allows one to omit the <command>FROM</command> clause from a query. This feature was retained from the original PostQuel query language. It has -a straightforward use to compute the results of simple constant -expressions: +a straightforward use to compute the results of simple expressions: <programlisting> SELECT 2+2; @@ -1062,6 +1106,11 @@ and later will warn if the implicit-FROM feature is used in a query that also contains an explicit FROM clause. </para> + + <para> + The table-function feature is a <productname>PostgreSQL</productname> + extension. + </para> </refsect2> <refsect2 id="R2-SQL-SELECT-5"> diff --git a/doc/src/sgml/ref/select_into.sgml b/doc/src/sgml/ref/select_into.sgml index 13e139ffbaa..8eed28791a1 100644 --- a/doc/src/sgml/ref/select_into.sgml +++ b/doc/src/sgml/ref/select_into.sgml @@ -1,5 +1,5 @@ <!-- -$Header: /cvsroot/pgsql/doc/src/sgml/ref/select_into.sgml,v 1.19 2002/08/28 14:35:37 momjian Exp $ +$Header: /cvsroot/pgsql/doc/src/sgml/ref/select_into.sgml,v 1.20 2002/08/29 00:17:01 tgl Exp $ PostgreSQL documentation --> @@ -29,20 +29,9 @@ SELECT [ ALL | DISTINCT [ ON ( <replaceable class="PARAMETER">expression</replac [ HAVING <replaceable class="PARAMETER">condition</replaceable> [, ...] ] [ { UNION | INTERSECT | EXCEPT } [ ALL ] <replaceable class="PARAMETER">select</replaceable> ] [ ORDER BY <replaceable class="PARAMETER">expression</replaceable> [ ASC | DESC | USING <replaceable class="PARAMETER">operator</replaceable> ] [, ...] ] - [ LIMIT [ <replaceable class="PARAMETER">start</replaceable> , ] { <replaceable class="PARAMETER">count</replaceable> | ALL } ] + [ LIMIT { <replaceable class="PARAMETER">count</replaceable> | ALL } ] [ OFFSET <replaceable class="PARAMETER">start</replaceable> ] [ FOR UPDATE [ OF <replaceable class="PARAMETER">tablename</replaceable> [, ...] ] ] - -where <replaceable class="PARAMETER">from_item</replaceable> can be: - -[ ONLY ] <replaceable class="PARAMETER">table_name</replaceable> [ * ] - [ [ AS ] <replaceable class="PARAMETER">alias</replaceable> [ ( <replaceable class="PARAMETER">column_alias_list</replaceable> ) ] ] -| -( <replaceable class="PARAMETER">select</replaceable> ) - [ AS ] <replaceable class="PARAMETER">alias</replaceable> [ ( <replaceable class="PARAMETER">column_alias_list</replaceable> ) ] -| -<replaceable class="PARAMETER">from_item</replaceable> [ NATURAL ] <replaceable class="PARAMETER">join_type</replaceable> <replaceable class="PARAMETER">from_item</replaceable> - [ ON <replaceable class="PARAMETER">join_condition</replaceable> | USING ( <replaceable class="PARAMETER">join_column_list</replaceable> ) ] </synopsis> <refsect2 id="R2-SQL-SELECTINTO-1"> diff --git a/doc/src/sgml/release.sgml b/doc/src/sgml/release.sgml index e457504ebef..60c78d0588f 100644 --- a/doc/src/sgml/release.sgml +++ b/doc/src/sgml/release.sgml @@ -1,5 +1,5 @@ <!-- -$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.152 2002/08/27 04:55:07 tgl Exp $ +$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.153 2002/08/29 00:17:01 tgl Exp $ --> <appendix id="release"> @@ -26,6 +26,7 @@ worries about funny characters. <literallayout><![CDATA[ PREPARE statement allows caching query plans for interactive statements Type OPAQUE is now deprecated in favor of pseudo-types cstring, trigger, etc +Standalone composite types can now be created with CREATE TYPE Files larger than 2 GB are now supported (if supported by the operating system) SERIAL no longer implies UNIQUE; specify explicitly if index is wanted pg_dump -n and -N options have been removed. The new behavior is like -n but knows about key words. diff --git a/doc/src/sgml/xfunc.sgml b/doc/src/sgml/xfunc.sgml index a38305ce0bc..b3f653a28a1 100644 --- a/doc/src/sgml/xfunc.sgml +++ b/doc/src/sgml/xfunc.sgml @@ -1,5 +1,5 @@ <!-- -$Header: /cvsroot/pgsql/doc/src/sgml/xfunc.sgml,v 1.56 2002/08/23 16:41:37 tgl Exp $ +$Header: /cvsroot/pgsql/doc/src/sgml/xfunc.sgml,v 1.57 2002/08/29 00:17:02 tgl Exp $ --> <chapter id="xfunc"> @@ -10,23 +10,6 @@ $Header: /cvsroot/pgsql/doc/src/sgml/xfunc.sgml,v 1.56 2002/08/23 16:41:37 tgl E <sect1 id="xfunc-intro"> <title>Introduction</title> - <comment> - Historically, functions were perhaps considered a tool for creating - types. Today, few people build their own types but many write - their own functions. This introduction ought to be changed to - reflect this. - </comment> - - <para> - As it turns out, part of defining a new type is the - definition of functions that describe its behavior. - Consequently, while it is possible to define a new - function without defining a new type, the reverse is - not true. We therefore describe how to add new functions - to <productname>PostgreSQL</productname> before describing - how to add new types. - </para> - <para> <productname>PostgreSQL</productname> provides four kinds of functions: @@ -285,8 +268,6 @@ SELECT name, double_salary(EMP) AS dream <para> It is also possible to build a function that returns a composite type. - (However, as we'll see below, there are some - unfortunate restrictions on how the function may be used.) This is an example of a function that returns a single <type>EMP</type> row: @@ -330,12 +311,12 @@ ERROR: function declared to return emp returns varchar instead of text at colum </para> <para> - In the present release of <productname>PostgreSQL</productname> - there are some unpleasant restrictions on how functions returning - composite types can be used. Briefly, when calling a function that - returns a row, we cannot retrieve the entire row. We must either + A function that returns a row (composite type) can be used as a table + function, as described below. It can also be called in the context + of an SQL expression, but only when you extract a single attribute out of the row or pass the entire row into - another function. (Trying to display the entire row value will yield + another function that accepts the same composite type. (Trying to + display the entire row value will yield a meaningless number.) For example, <programlisting> @@ -357,8 +338,8 @@ ERROR: parser: parse error at or near "." </para> <para> - Another approach is to use - functional notation for extracting attributes. The simple way + Another option is to use + functional notation for extracting an attribute. The simple way to explain this is that we can use the notations <literal>attribute(table)</> and <literal>table.attribute</> interchangeably: @@ -412,26 +393,73 @@ SELECT getname(new_emp()); </sect2> <sect2> - <title><acronym>SQL</acronym> Table Functions (Functions Returning Sets)</title> + <title><acronym>SQL</acronym> Table Functions</title> <para> A table function is one that may be used in the <command>FROM</command> - clause of a query. All SQL Language functions may be used in this manner. + clause of a query. All SQL language functions may be used in this manner, + but it is particularly useful for functions returning composite types. If the function is defined to return a base type, the table function - produces a one column result set. If the function is defined to - return <literal>SETOF <replaceable>sometype</></literal>, the table - function returns multiple rows. To illustrate a SQL table function, - consider the following, which returns <literal>SETOF</literal> a - composite type: + produces a one-column table. If the function is defined to return + a composite type, the table function produces a column for each column + of the composite type. + </para> + + <para> + Here is an example: <programlisting> -CREATE TABLE foo (fooid int, foosubid int, fooname text, primary key(fooid,foosubid)); +CREATE TABLE foo (fooid int, foosubid int, fooname text); INSERT INTO foo VALUES(1,1,'Joe'); INSERT INTO foo VALUES(1,2,'Ed'); INSERT INTO foo VALUES(2,1,'Mary'); + +CREATE FUNCTION getfoo(int) RETURNS foo AS ' + SELECT * FROM foo WHERE fooid = $1; +' LANGUAGE SQL; + +SELECT *, upper(fooname) FROM getfoo(1) AS t1; +</programlisting> + +<screen> + fooid | foosubid | fooname | upper +-------+----------+---------+------- + 1 | 1 | Joe | JOE +(2 rows) +</screen> + + As the example shows, we can work with the columns of the function's + result just the same as if they were columns of a regular table. + </para> + + <para> + Note that we only got one row out of the function. This is because + we did not say <literal>SETOF</>. + </para> + + </sect2> + + <sect2> + <title><acronym>SQL</acronym> Functions Returning Sets</title> + + <para> + When an SQL function is declared as returning <literal>SETOF</literal> + <replaceable>sometype</>, the function's final + <command>SELECT</> query is executed to completion, and each row it + outputs is returned as an element of the set. + </para> + + <para> + This feature is normally used by calling the function as a table + function. In this case each row returned by the function becomes + a row of the table seen by the query. For example, assume that + table <literal>foo</> has the same contents as above, and we say: + +<programlisting> CREATE FUNCTION getfoo(int) RETURNS setof foo AS ' SELECT * FROM foo WHERE fooid = $1; ' LANGUAGE SQL; + SELECT * FROM getfoo(1) AS t1; </programlisting> @@ -445,14 +473,7 @@ SELECT * FROM getfoo(1) AS t1; </para> <para> - When an SQL function is declared as returning <literal>SETOF - <replaceable>sometype</></literal>, the function's final - <command>SELECT</> query is executed to completion, and each row it - outputs is returned as an element of the set. - </para> - - <para> - Functions returning sets may also currently be called in the target list + Currently, functions returning sets may also be called in the target list of a <command>SELECT</> query. For each row that the <command>SELECT</> generates by itself, the function returning set is invoked, and an output row is generated for each element of the function's result set. Note, @@ -1346,7 +1367,8 @@ concat_text(PG_FUNCTION_ARGS) <function>PG_GETARG_<replaceable>xxx</replaceable>_COPY()</function> guarantees to return a copy of the specified parameter which is safe for writing into. (The normal macros will sometimes return a - pointer to the value which must not be written to. Using the + pointer to a value that is physically stored in a table, and so + must not be written to. Using the <function>PG_GETARG_<replaceable>xxx</replaceable>_COPY()</function> macros guarantees a writable result.) </para> @@ -1471,8 +1493,8 @@ LANGUAGE C; <title>Table Function API</title> <para> - The Table Function API assists in the creation of a user defined - C Language table functions (<xref linkend="xfunc-tablefunctions">). + The Table Function API assists in the creation of user-defined + C language table functions (<xref linkend="xfunc-tablefunctions">). Table functions are functions that produce a set of rows, made up of either base (scalar) data types, or composite (multi-column) data types. The API is split into two main components: support for returning @@ -1482,105 +1504,124 @@ LANGUAGE C; <para> The Table Function API relies on macros and functions to suppress most - of the complexity of building composite data types and return multiple - results. In addition to the version-1 conventions discussed elsewhere, - a table function always requires the following: + of the complexity of building composite data types and returning multiple + results. A table function must follow the version-1 calling convention + described above. In addition, the source file must include: <programlisting> #include "funcapi.h" </programlisting> </para> + <sect3> + <title>Returning Tuples (Composite Types)</title> + <para> The Table Function API support for returning composite data types (or tuples) starts with the AttInMetadata struct. This struct holds arrays of individual attribute information needed to create a tuple from - raw C strings. It also requires a copy of the TupleDesc. The information + raw C strings. It also saves a pointer to the TupleDesc. The information carried here is derived from the TupleDesc, but it is stored here to - avoid redundant cpu cycles on each call to a Table Function. + avoid redundant CPU cycles on each call to a Table Function. In the + case of a function returning a set, the AttInMetadata struct should be + computed once during the first call and saved for re-use in later calls. <programlisting> -typedef struct +typedef struct AttInMetadata { - /* full TupleDesc */ - TupleDesc tupdesc; - - /* pointer to array of attribute "type"in finfo */ - FmgrInfo *attinfuncs; + /* full TupleDesc */ + TupleDesc tupdesc; - /* pointer to array of attribute type typelem */ - Oid *attelems; + /* array of attribute type input function finfo */ + FmgrInfo *attinfuncs; - /* pointer to array of attribute type typtypmod */ - int4 *atttypmods; + /* array of attribute type typelem */ + Oid *attelems; + /* array of attribute typmod */ + int32 *atttypmods; } AttInMetadata; </programlisting> To assist you in populating this struct, several functions and a macro are available. Use <programlisting> -TupleDesc RelationNameGetTupleDesc(char *relname) +TupleDesc RelationNameGetTupleDesc(const char *relname) </programlisting> - to get a TupleDesc based on the function's return type relation, or + to get a TupleDesc based on a specified relation, or <programlisting> TupleDesc TypeGetTupleDesc(Oid typeoid, List *colaliases) </programlisting> - to get a TupleDesc based on the function's type oid. This can be used to - get a TupleDesc for a base (scalar), or composite (relation) type. Then + to get a TupleDesc based on a type OID. This can be used to + get a TupleDesc for a base (scalar) or composite (relation) type. Then <programlisting> AttInMetadata *TupleDescGetAttInMetadata(TupleDesc tupdesc) </programlisting> will return a pointer to an AttInMetadata struct, initialized based on - the function's TupleDesc. AttInMetadata is be used in conjunction with + the given TupleDesc. AttInMetadata can be used in conjunction with C strings to produce a properly formed tuple. The metadata is stored here - for use across calls to avoid redundant work. + to avoid redundant work across multiple calls. </para> <para> - In order to return a tuple you must create a tuple slot based on the + To return a tuple you must create a tuple slot based on the TupleDesc. You can use <programlisting> TupleTableSlot *TupleDescGetSlot(TupleDesc tupdesc) </programlisting> 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. + function. The same slot can (and should) be re-used on each call. </para> <para> - If desired, + After constructing an AttInMetadata structure, <programlisting> HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values) </programlisting> 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 - tuple. The C strings should be in the form expected by the "in" function - of the attribute data type. For more information on this requirement, - see the individual data type "in" functions in the source code - (e.g. textin() for data type TEXT). In order to return a NULL value for + tuple. 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 - should be set to NULL. + should be set to NULL. This function will need to be called again + for each tuple you return. </para> <para> - In order to get an attribute "in" function and typelem value given the - typeid, use -<programlisting> -void get_type_metadata(Oid typeid, Oid *attinfuncid, Oid *attelem) -</programlisting> + 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 Datums, you should instead use the underlying + heap_formtuple routine to convert the Datums directly into a tuple. + You will still need the TupleDesc and a TupleTableSlot, but not + AttInMetadata. </para> <para> - Finally, in order to return a tuple using the SRF portion of the API - (described below), the tuple must be converted into a Datum. Use + Once you have built a tuple to return from your function, the tuple must + be converted into a Datum. Use <programlisting> TupleGetDatum(TupleTableSlot *slot, HeapTuple tuple) </programlisting> - to get a Datum given a tuple and a slot. + to get a Datum given a tuple and a slot. 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. + </para> + + <para> + An example appears below. </para> + </sect3> + + <sect3> + <title>Returning Sets</title> + <para> - The Table Function API support for set returning functions starts with - the FuncCallContext struct. This struct holds function context for - SRFs using fcinfo->flinfo->fn_extra to hold a pointer to it across calls. + A set-returning function (SRF) is normally called once for each item it + returns. The SRF must therefore save enough state to remember what it + was doing and return the next item on each call. The Table Function API + provides the FuncCallContext struct to help control this process. + <literal>fcinfo->flinfo->fn_extra</> is used to + hold a pointer to FuncCallContext across calls. <programlisting> typedef struct { @@ -1639,12 +1680,13 @@ typedef struct } FuncCallContext; </programlisting> - To assist you in populating this struct, several functions and macros - are available. Use + An SRF uses several functions and macros that automatically manipulate + the FuncCallContext struct (and expect to find it via + <literal>fn_extra</>). Use <programlisting> SRF_IS_FIRSTCALL() </programlisting> - to determine if your function has been called for the first or a + to determine if your function is being called for the first or a subsequent time. On the first call (only) use <programlisting> SRF_FIRSTCALL_INIT() @@ -1663,8 +1705,9 @@ SRF_PERCALL_SETUP() <programlisting> SRF_RETURN_NEXT(funcctx, result) </programlisting> - to send it and prepare for the next call. Finally, when your function - is finished returning data, use + to return it to the caller. (The <literal>result</> + must be a Datum, either a single value or a tuple prepared as described + earlier.) Finally, when your function is finished returning data, use <programlisting> SRF_RETURN_DONE(funcctx) </programlisting> @@ -1677,136 +1720,139 @@ SRF_RETURN_DONE(funcctx) Datum my_Set_Returning_Function(PG_FUNCTION_ARGS) { - FuncCallContext *funcctx; - Datum result; - - [user defined declarations] - - if(SRF_IS_FIRSTCALL()) - { - [user defined code] - funcctx = SRF_FIRSTCALL_INIT(); - [if returning composite] - [obtain slot] - funcctx->slot = slot; - [endif returning composite] - [user defined code] - } - [user defined code] - funcctx = SRF_PERCALL_SETUP(); - [user defined code] - - if (funcctx->call_cntr < funcctx->max_calls) - { - [user defined code] - [obtain result Datum] - SRF_RETURN_NEXT(funcctx, result); - } - else - { - SRF_RETURN_DONE(funcctx); - } + FuncCallContext *funcctx; + Datum result; + [user defined declarations] + + if (SRF_IS_FIRSTCALL()) + { + /* one-time setup code appears here: */ + [user defined code] + funcctx = SRF_FIRSTCALL_INIT(); + [if returning composite] + [build TupleDesc, and perhaps AttInMetadata] + [obtain slot] + funcctx->slot = slot; + [endif returning composite] + [user defined code] + } + + /* each-time setup code appears here: */ + [user defined code] + funcctx = SRF_PERCALL_SETUP(); + [user defined code] + + /* this is just one way we might test whether we are done: */ + if (funcctx->call_cntr < funcctx->max_calls) + { + /* here we want to return another item: */ + [user defined code] + [obtain result Datum] + SRF_RETURN_NEXT(funcctx, result); + } + else + { + /* here we are done returning items, and just need to clean up: */ + [user defined code] + SRF_RETURN_DONE(funcctx); + } } </programlisting> </para> <para> - An example of a simple composite returning SRF looks like: + A complete example of a simple SRF returning a composite type looks like: <programlisting> PG_FUNCTION_INFO_V1(testpassbyval); Datum testpassbyval(PG_FUNCTION_ARGS) { - FuncCallContext *funcctx; - int call_cntr; - int max_calls; - TupleDesc tupdesc; - TupleTableSlot *slot; - AttInMetadata *attinmeta; + FuncCallContext *funcctx; + int call_cntr; + int max_calls; + TupleDesc tupdesc; + TupleTableSlot *slot; + AttInMetadata *attinmeta; + + /* stuff done only on the first call of the function */ + if (SRF_IS_FIRSTCALL()) + { + /* create a function context for cross-call persistence */ + funcctx = SRF_FIRSTCALL_INIT(); + + /* total number of tuples to be returned */ + funcctx->max_calls = PG_GETARG_UINT32(0); - /* stuff done only on the first call of the function */ - if(SRF_IS_FIRSTCALL()) - { - /* create a function context for cross-call persistence */ - funcctx = SRF_FIRSTCALL_INIT(); - - /* total number of tuples to be returned */ - funcctx->max_calls = PG_GETARG_UINT32(0); - - /* - * Build a tuple description for a __testpassbyval tuple - */ - tupdesc = RelationNameGetTupleDesc("__testpassbyval"); + /* + * Build a tuple description for a __testpassbyval tuple + */ + tupdesc = RelationNameGetTupleDesc("__testpassbyval"); - /* allocate a slot for a tuple with this tupdesc */ - slot = TupleDescGetSlot(tupdesc); + /* allocate a slot for a tuple with this tupdesc */ + slot = TupleDescGetSlot(tupdesc); - /* assign slot to function context */ - funcctx->slot = slot; + /* assign slot to function context */ + funcctx->slot = slot; - /* - * Generate attribute metadata needed later to produce tuples from raw - * C strings - */ - attinmeta = TupleDescGetAttInMetadata(tupdesc); - funcctx->attinmeta = attinmeta; + /* + * Generate attribute metadata needed later to produce tuples from raw + * C strings + */ + attinmeta = TupleDescGetAttInMetadata(tupdesc); + funcctx->attinmeta = attinmeta; } - /* stuff done on every call of the function */ - funcctx = SRF_PERCALL_SETUP(); + /* stuff done on every call of the function */ + funcctx = SRF_PERCALL_SETUP(); - call_cntr = funcctx->call_cntr; - max_calls = funcctx->max_calls; - slot = funcctx->slot; - attinmeta = funcctx->attinmeta; + 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 */ - { - char **values; - HeapTuple tuple; - Datum result; - - /* - * Prepare a values array for storage in our slot. - * This should be an array of C strings which will - * be processed later by the appropriate "in" functions. - */ - values = (char **) palloc(3 * sizeof(char *)); - values[0] = (char *) palloc(16 * sizeof(char)); - values[1] = (char *) palloc(16 * sizeof(char)); - values[2] = (char *) palloc(16 * sizeof(char)); - - snprintf(values[0], 16, "%d", 1 * PG_GETARG_INT32(1)); - snprintf(values[1], 16, "%d", 2 * PG_GETARG_INT32(1)); - snprintf(values[2], 16, "%d", 3 * PG_GETARG_INT32(1)); - - /* build a tuple */ - tuple = BuildTupleFromCStrings(attinmeta, values); - - /* make the tuple into a datum */ - result = TupleGetDatum(slot, tuple); - - /* Clean up */ - pfree(values[0]); - pfree(values[1]); - pfree(values[2]); - pfree(values); - - SRF_RETURN_NEXT(funcctx, result); - } - else /* do when there is no more left */ - { - SRF_RETURN_DONE(funcctx); - } + if (call_cntr < max_calls) /* do when there is more left to send */ + { + char **values; + HeapTuple tuple; + Datum result; + + /* + * Prepare a values array for storage in our slot. + * This should be an array of C strings which will + * be processed later by the appropriate "in" functions. + */ + values = (char **) palloc(3 * sizeof(char *)); + values[0] = (char *) palloc(16 * sizeof(char)); + values[1] = (char *) palloc(16 * sizeof(char)); + values[2] = (char *) palloc(16 * sizeof(char)); + + snprintf(values[0], 16, "%d", 1 * PG_GETARG_INT32(1)); + snprintf(values[1], 16, "%d", 2 * PG_GETARG_INT32(1)); + snprintf(values[2], 16, "%d", 3 * PG_GETARG_INT32(1)); + + /* build a tuple */ + tuple = BuildTupleFromCStrings(attinmeta, values); + + /* make the tuple into a datum */ + result = TupleGetDatum(slot, tuple); + + /* Clean up */ + pfree(values[0]); + pfree(values[1]); + pfree(values[2]); + pfree(values); + + SRF_RETURN_NEXT(funcctx, result); + } + else /* do when there is no more left */ + { + SRF_RETURN_DONE(funcctx); + } } </programlisting> with supporting SQL code of <programlisting> -CREATE VIEW __testpassbyval AS - SELECT - 0::INT4 AS f1, - 0::INT4 AS f2, - 0::INT4 AS f3; +CREATE TYPE __testpassbyval AS (f1 int4, f2 int4, f3 int4); CREATE OR REPLACE FUNCTION testpassbyval(int4, int4) RETURNS setof __testpassbyval AS 'MODULE_PATHNAME','testpassbyval' LANGUAGE 'c' IMMUTABLE STRICT; @@ -1816,6 +1862,9 @@ CREATE OR REPLACE FUNCTION testpassbyval(int4, int4) RETURNS setof __testpassbyv <para> See contrib/tablefunc for more examples of Table Functions. </para> + + </sect3> + </sect2> <sect2> @@ -2031,23 +2080,23 @@ CREATE FUNCTION test(int, int) RETURNS int Table functions work wherever tables do in <literal>SELECT</> statements. For example <programlisting> -CREATE TABLE foo (fooid int, foosubid int, fooname text, primary key(fooid,foosubid)); -CREATE FUNCTION getfoo(int) RETURNS foo AS 'SELECT * FROM foo WHERE fooid = $1;' LANGUAGE SQL; +CREATE TABLE foo (fooid int, foosubid int, fooname text); + +CREATE FUNCTION getfoo(int) RETURNS setof foo AS ' + SELECT * FROM foo WHERE fooid = $1; +' LANGUAGE SQL; + SELECT * FROM getfoo(1) AS t1; -SELECT * FROM foo where foosubid in (select foosubid from getfoo(foo.fooid) z where z.fooid = foo.fooid); + +SELECT * FROM foo +WHERE foosubid in (select foosubid from getfoo(foo.fooid) z + where z.fooid = foo.fooid); + CREATE VIEW vw_getfoo AS SELECT * FROM getfoo(1); SELECT * FROM vw_getfoo; </programlisting> are all valid statements. </para> - - <para> - Currently, table functions are supported as SQL language functions - (<xref linkend="xfunc-sql">) and C language functions - (<xref linkend="xfunc-c">). See these individual sections for more - details. - </para> - </sect1> <sect1 id="xfunc-plhandler"> |
