mirror of
https://github.com/postgres/postgres.git
synced 2025-06-16 06:01:02 +03:00
Implement SQL-spec RETURNS TABLE syntax for functions.
(Unlike the original submission, this patch treats TABLE output parameters as being entirely equivalent to OUT parameters -- tgl) Pavel Stehule
This commit is contained in:
@ -1,4 +1,4 @@
|
|||||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.170 2008/07/16 16:55:23 tgl Exp $ -->
|
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.171 2008/07/18 03:32:51 tgl Exp $ -->
|
||||||
<!--
|
<!--
|
||||||
Documentation of the system catalogs, directed toward PostgreSQL developers
|
Documentation of the system catalogs, directed toward PostgreSQL developers
|
||||||
-->
|
-->
|
||||||
@ -3680,7 +3680,8 @@
|
|||||||
<literal>i</literal> for <literal>IN</> arguments,
|
<literal>i</literal> for <literal>IN</> arguments,
|
||||||
<literal>o</literal> for <literal>OUT</> arguments,
|
<literal>o</literal> for <literal>OUT</> arguments,
|
||||||
<literal>b</literal> for <literal>INOUT</> arguments,
|
<literal>b</literal> for <literal>INOUT</> arguments,
|
||||||
<literal>v</literal> for <literal>VARIADIC</> arguments.
|
<literal>v</literal> for <literal>VARIADIC</> arguments,
|
||||||
|
<literal>t</literal> for <literal>TABLE</> arguments.
|
||||||
If all the arguments are <literal>IN</literal> arguments,
|
If all the arguments are <literal>IN</literal> arguments,
|
||||||
this field will be null.
|
this field will be null.
|
||||||
Note that subscripts correspond to positions of
|
Note that subscripts correspond to positions of
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.441 2008/07/16 00:48:53 momjian Exp $ -->
|
<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.442 2008/07/18 03:32:51 tgl Exp $ -->
|
||||||
|
|
||||||
<chapter id="functions">
|
<chapter id="functions">
|
||||||
<title>Functions and Operators</title>
|
<title>Functions and Operators</title>
|
||||||
@ -11563,6 +11563,14 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
|
|||||||
<primary>pg_get_ruledef</primary>
|
<primary>pg_get_ruledef</primary>
|
||||||
</indexterm>
|
</indexterm>
|
||||||
|
|
||||||
|
<indexterm>
|
||||||
|
<primary>pg_get_function_arguments</primary>
|
||||||
|
</indexterm>
|
||||||
|
|
||||||
|
<indexterm>
|
||||||
|
<primary>pg_get_function_result</primary>
|
||||||
|
</indexterm>
|
||||||
|
|
||||||
<indexterm>
|
<indexterm>
|
||||||
<primary>pg_get_indexdef</primary>
|
<primary>pg_get_indexdef</primary>
|
||||||
</indexterm>
|
</indexterm>
|
||||||
@ -11636,6 +11644,16 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
|
|||||||
<entry>decompile internal form of an expression, assuming that any Vars
|
<entry>decompile internal form of an expression, assuming that any Vars
|
||||||
in it refer to the relation indicated by the second parameter</entry>
|
in it refer to the relation indicated by the second parameter</entry>
|
||||||
</row>
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry><literal><function>pg_get_function_arguments</function>(<parameter>func_oid</parameter>)</literal></entry>
|
||||||
|
<entry><type>text</type></entry>
|
||||||
|
<entry>get argument list for function</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry><literal><function>pg_get_function_result</function>(<parameter>func_oid</parameter>)</literal></entry>
|
||||||
|
<entry><type>text</type></entry>
|
||||||
|
<entry>get <literal>RETURNS</> clause for function</entry>
|
||||||
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry><literal><function>pg_get_indexdef</function>(<parameter>index_oid</parameter>)</literal></entry>
|
<entry><literal><function>pg_get_indexdef</function>(<parameter>index_oid</parameter>)</literal></entry>
|
||||||
<entry><type>text</type></entry>
|
<entry><type>text</type></entry>
|
||||||
@ -11738,6 +11756,14 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
|
|||||||
the same result as the variant that does not have the parameter at all.
|
the same result as the variant that does not have the parameter at all.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
<function>pg_get_function_arguments</function> returns the argument list
|
||||||
|
of a function, in the form it would need to appear in within
|
||||||
|
<command>CREATE FUNCTION</>.
|
||||||
|
<function>pg_get_function_result</function> similarly returns the
|
||||||
|
appropriate <literal>RETURNS</> clause for the function.
|
||||||
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
<function>pg_get_serial_sequence</function> returns the name of the
|
<function>pg_get_serial_sequence</function> returns the name of the
|
||||||
sequence associated with a column, or NULL if no sequence is associated
|
sequence associated with a column, or NULL if no sequence is associated
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.132 2008/07/16 01:30:21 tgl Exp $ -->
|
<!-- $PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.133 2008/07/18 03:32:51 tgl Exp $ -->
|
||||||
|
|
||||||
<chapter id="plpgsql">
|
<chapter id="plpgsql">
|
||||||
<title><application>PL/pgSQL</application> - <acronym>SQL</acronym> Procedural Language</title>
|
<title><application>PL/pgSQL</application> - <acronym>SQL</acronym> Procedural Language</title>
|
||||||
@ -157,6 +157,8 @@
|
|||||||
parameters in place of an explicit specification of the return type.
|
parameters in place of an explicit specification of the return type.
|
||||||
This does not add any fundamental capability to the language, but
|
This does not add any fundamental capability to the language, but
|
||||||
it is often convenient, especially for returning multiple values.
|
it is often convenient, especially for returning multiple values.
|
||||||
|
The <literal>RETURNS TABLE</> notation can also be used in place
|
||||||
|
of <literal>RETURNS SETOF</>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@ -468,6 +470,23 @@ $$ LANGUAGE plpgsql;
|
|||||||
<literal>RETURNS record</>.
|
<literal>RETURNS record</>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Another way to declare a <application>PL/pgSQL</application> function
|
||||||
|
is with <literal>RETURNS TABLE</>, for example:
|
||||||
|
|
||||||
|
<programlisting>
|
||||||
|
CREATE FUNCTION extended_sales(p_itemno int) RETURNS TABLE(quantity int, total numeric) AS $$
|
||||||
|
BEGIN
|
||||||
|
RETURN QUERY SELECT quantity, quantity * price FROM sales WHERE itemno = p_itemno;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
This is exactly equivalent to declaring one or more <literal>OUT</>
|
||||||
|
parameters and specifying <literal>RETURNS SETOF
|
||||||
|
<replaceable>sometype</></literal>.
|
||||||
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
When the return type of a <application>PL/pgSQL</application>
|
When the return type of a <application>PL/pgSQL</application>
|
||||||
function is declared as a polymorphic type (<type>anyelement</type>,
|
function is declared as a polymorphic type (<type>anyelement</type>,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$PostgreSQL: pgsql/doc/src/sgml/ref/create_function.sgml,v 1.79 2008/07/16 01:30:21 tgl Exp $
|
$PostgreSQL: pgsql/doc/src/sgml/ref/create_function.sgml,v 1.80 2008/07/18 03:32:52 tgl Exp $
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<refentry id="SQL-CREATEFUNCTION">
|
<refentry id="SQL-CREATEFUNCTION">
|
||||||
@ -21,7 +21,8 @@ $PostgreSQL: pgsql/doc/src/sgml/ref/create_function.sgml,v 1.79 2008/07/16 01:30
|
|||||||
<synopsis>
|
<synopsis>
|
||||||
CREATE [ OR REPLACE ] FUNCTION
|
CREATE [ OR REPLACE ] FUNCTION
|
||||||
<replaceable class="parameter">name</replaceable> ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] )
|
<replaceable class="parameter">name</replaceable> ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] )
|
||||||
[ RETURNS <replaceable class="parameter">rettype</replaceable> ]
|
[ RETURNS <replaceable class="parameter">rettype</replaceable>
|
||||||
|
| RETURNS TABLE ( <replaceable class="parameter">colname</replaceable> <replaceable class="parameter">coltype</replaceable> [, ...] ) ]
|
||||||
{ LANGUAGE <replaceable class="parameter">langname</replaceable>
|
{ LANGUAGE <replaceable class="parameter">langname</replaceable>
|
||||||
| IMMUTABLE | STABLE | VOLATILE
|
| IMMUTABLE | STABLE | VOLATILE
|
||||||
| CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT
|
| CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT
|
||||||
@ -49,7 +50,7 @@ CREATE [ OR REPLACE ] FUNCTION
|
|||||||
If a schema name is included, then the function is created in the
|
If a schema name is included, then the function is created in the
|
||||||
specified schema. Otherwise it is created in the current schema.
|
specified schema. Otherwise it is created in the current schema.
|
||||||
The name of the new function must not match any existing function
|
The name of the new function must not match any existing function
|
||||||
with the same argument types in the same schema. However,
|
with the same input argument types in the same schema. However,
|
||||||
functions of different argument types can share a name (this is
|
functions of different argument types can share a name (this is
|
||||||
called <firstterm>overloading</>).
|
called <firstterm>overloading</>).
|
||||||
</para>
|
</para>
|
||||||
@ -104,6 +105,9 @@ CREATE [ OR REPLACE ] FUNCTION
|
|||||||
The mode of an argument: <literal>IN</>, <literal>OUT</>,
|
The mode of an argument: <literal>IN</>, <literal>OUT</>,
|
||||||
<literal>INOUT</>, or <literal>VARIADIC</>.
|
<literal>INOUT</>, or <literal>VARIADIC</>.
|
||||||
If omitted, the default is <literal>IN</>.
|
If omitted, the default is <literal>IN</>.
|
||||||
|
Only <literal>OUT</> arguments can follow a <literal>VARIADIC</> one.
|
||||||
|
Also, <literal>OUT</> and <literal>INOUT</> arguments cannot be used
|
||||||
|
together with the <literal>RETURNS TABLE</> notation.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
@ -183,6 +187,30 @@ CREATE [ OR REPLACE ] FUNCTION
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><replaceable class="parameter">colname</replaceable></term>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The name of an output column in the <literal>RETURNS TABLE</>
|
||||||
|
syntax. This is effectively another way of declaring a named
|
||||||
|
<literal>OUT</> parameter, except that <literal>RETURNS TABLE</>
|
||||||
|
also implies <literal>RETURNS SETOF</>.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><replaceable class="parameter">coltype</replaceable></term>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The data type of an output column in the <literal>RETURNS TABLE</>
|
||||||
|
syntax.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><replaceable class="parameter">langname</replaceable></term>
|
<term><replaceable class="parameter">langname</replaceable></term>
|
||||||
|
|
||||||
@ -437,7 +465,7 @@ CREATE [ OR REPLACE ] FUNCTION
|
|||||||
<productname>PostgreSQL</productname> allows function
|
<productname>PostgreSQL</productname> allows function
|
||||||
<firstterm>overloading</firstterm>; that is, the same name can be
|
<firstterm>overloading</firstterm>; that is, the same name can be
|
||||||
used for several different functions so long as they have distinct
|
used for several different functions so long as they have distinct
|
||||||
argument types. However, the C names of all functions must be
|
input argument types. However, the C names of all functions must be
|
||||||
different, so you must give overloaded C functions different C
|
different, so you must give overloaded C functions different C
|
||||||
names (for example, use the argument types as part of the C
|
names (for example, use the argument types as part of the C
|
||||||
names).
|
names).
|
||||||
@ -541,6 +569,18 @@ CREATE FUNCTION dup(int) RETURNS dup_result
|
|||||||
|
|
||||||
SELECT * FROM dup(42);
|
SELECT * FROM dup(42);
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
Another way to return multiple columns is to use a <literal>TABLE</>
|
||||||
|
function:
|
||||||
|
<programlisting>
|
||||||
|
CREATE FUNCTION dup(int) RETURNS TABLE(f1 int, f2 text)
|
||||||
|
AS $$ SELECT $1, CAST($1 AS text) || ' is text' $$
|
||||||
|
LANGUAGE SQL;
|
||||||
|
|
||||||
|
SELECT * FROM dup(42);
|
||||||
|
</programlisting>
|
||||||
|
However, a <literal>TABLE</> function is different from the
|
||||||
|
preceding examples, because it actually returns a <emphasis>set</>
|
||||||
|
of records, not just one record.
|
||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/xfunc.sgml,v 1.131 2008/07/16 01:30:21 tgl Exp $ -->
|
<!-- $PostgreSQL: pgsql/doc/src/sgml/xfunc.sgml,v 1.132 2008/07/18 03:32:52 tgl Exp $ -->
|
||||||
|
|
||||||
<sect1 id="xfunc">
|
<sect1 id="xfunc">
|
||||||
<title>User-Defined Functions</title>
|
<title>User-Defined Functions</title>
|
||||||
@ -94,11 +94,12 @@
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
<indexterm><primary>SETOF</><seealso>function</></> Alternatively,
|
Alternatively, an SQL function can be declared to return a set,
|
||||||
an SQL function can be declared to return a set, by specifying the
|
by specifying the function's return type as <literal>SETOF
|
||||||
function's return type as <literal>SETOF
|
<replaceable>sometype</></literal>, or equivalently by declaring it as
|
||||||
<replaceable>sometype</></literal>. In this case all rows of the
|
<literal>RETURNS TABLE(<replaceable>columns</>)</literal>. In this case
|
||||||
last query's result are returned. Further details appear below.
|
all rows of the last query's result are returned. Further details appear
|
||||||
|
below.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@ -117,7 +118,7 @@
|
|||||||
other SQL commands. (The only exception is that you cannot put
|
other SQL commands. (The only exception is that you cannot put
|
||||||
<command>BEGIN</>, <command>COMMIT</>, <command>ROLLBACK</>, or
|
<command>BEGIN</>, <command>COMMIT</>, <command>ROLLBACK</>, or
|
||||||
<command>SAVEPOINT</> commands into a <acronym>SQL</acronym> function.)
|
<command>SAVEPOINT</> commands into a <acronym>SQL</acronym> function.)
|
||||||
However, the final command
|
However, the final command
|
||||||
must be a <command>SELECT</command> that returns whatever is
|
must be a <command>SELECT</command> that returns whatever is
|
||||||
specified as the function's return type. Alternatively, if you
|
specified as the function's return type. Alternatively, if you
|
||||||
want to define a SQL function that performs actions but has no
|
want to define a SQL function that performs actions but has no
|
||||||
@ -175,7 +176,7 @@ INSERT INTO $1 VALUES (42);
|
|||||||
<para>
|
<para>
|
||||||
The simplest possible <acronym>SQL</acronym> function has no arguments and
|
The simplest possible <acronym>SQL</acronym> function has no arguments and
|
||||||
simply returns a base type, such as <type>integer</type>:
|
simply returns a base type, such as <type>integer</type>:
|
||||||
|
|
||||||
<screen>
|
<screen>
|
||||||
CREATE FUNCTION one() RETURNS integer AS $$
|
CREATE FUNCTION one() RETURNS integer AS $$
|
||||||
SELECT 1 AS result;
|
SELECT 1 AS result;
|
||||||
@ -202,7 +203,7 @@ SELECT one();
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
It is almost as easy to define <acronym>SQL</acronym> functions
|
It is almost as easy to define <acronym>SQL</acronym> functions
|
||||||
that take base types as arguments. In the example below, notice
|
that take base types as arguments. In the example below, notice
|
||||||
how we refer to the arguments within the function as <literal>$1</>
|
how we refer to the arguments within the function as <literal>$1</>
|
||||||
and <literal>$2</>.
|
and <literal>$2</>.
|
||||||
@ -226,7 +227,7 @@ SELECT add_em(1, 2) AS answer;
|
|||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
CREATE FUNCTION tf1 (integer, numeric) RETURNS integer AS $$
|
CREATE FUNCTION tf1 (integer, numeric) RETURNS integer AS $$
|
||||||
UPDATE bank
|
UPDATE bank
|
||||||
SET balance = balance - $2
|
SET balance = balance - $2
|
||||||
WHERE accountno = $1;
|
WHERE accountno = $1;
|
||||||
SELECT 1;
|
SELECT 1;
|
||||||
@ -248,7 +249,7 @@ SELECT tf1(17, 100.0);
|
|||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
CREATE FUNCTION tf1 (integer, numeric) RETURNS numeric AS $$
|
CREATE FUNCTION tf1 (integer, numeric) RETURNS numeric AS $$
|
||||||
UPDATE bank
|
UPDATE bank
|
||||||
SET balance = balance - $2
|
SET balance = balance - $2
|
||||||
WHERE accountno = $1;
|
WHERE accountno = $1;
|
||||||
SELECT balance FROM bank WHERE accountno = $1;
|
SELECT balance FROM bank WHERE accountno = $1;
|
||||||
@ -267,7 +268,7 @@ $$ LANGUAGE SQL;
|
|||||||
types, we must not only specify which
|
types, we must not only specify which
|
||||||
argument we want (as we did above with <literal>$1</> and <literal>$2</literal>) but
|
argument we want (as we did above with <literal>$1</> and <literal>$2</literal>) but
|
||||||
also the desired attribute (field) of that argument. For example,
|
also the desired attribute (field) of that argument. For example,
|
||||||
suppose that
|
suppose that
|
||||||
<type>emp</type> is a table containing employee data, and therefore
|
<type>emp</type> is a table containing employee data, and therefore
|
||||||
also the name of the composite type of each row of the table. Here
|
also the name of the composite type of each row of the table. Here
|
||||||
is a function <function>double_salary</function> that computes what someone's
|
is a function <function>double_salary</function> that computes what someone's
|
||||||
@ -323,7 +324,7 @@ SELECT name, double_salary(ROW(name, salary*1.1, age, cubicle)) AS dream
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
It is also possible to build a function that returns a composite type.
|
It is also possible to build a function that returns a composite type.
|
||||||
This is an example of a function
|
This is an example of a function
|
||||||
that returns a single <type>emp</type> row:
|
that returns a single <type>emp</type> row:
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
@ -364,7 +365,7 @@ ERROR: function declared to return emp returns varchar instead of text at colum
|
|||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
A different way to define the same function is:
|
A different way to define the same function is:
|
||||||
@ -380,7 +381,7 @@ $$ LANGUAGE SQL;
|
|||||||
in this situation, but it is a handy alternative in some cases
|
in this situation, but it is a handy alternative in some cases
|
||||||
— for example, if we need to compute the result by calling
|
— for example, if we need to compute the result by calling
|
||||||
another function that returns the desired composite value.
|
another function that returns the desired composite value.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
We could call this function directly in either of two ways:
|
We could call this function directly in either of two ways:
|
||||||
@ -401,7 +402,7 @@ SELECT * FROM new_emp();
|
|||||||
|
|
||||||
The second way is described more fully in <xref
|
The second way is described more fully in <xref
|
||||||
linkend="xfunc-sql-table-functions">.
|
linkend="xfunc-sql-table-functions">.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
When you use a function that returns a composite type,
|
When you use a function that returns a composite type,
|
||||||
@ -429,7 +430,7 @@ LINE 1: SELECT new_emp().name;
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
Another option is to use
|
Another option is to use
|
||||||
functional notation for extracting an attribute. The simple way
|
functional notation for extracting an attribute. The simple way
|
||||||
to explain this is that we can use the
|
to explain this is that we can use the
|
||||||
notations <literal>attribute(table)</> and <literal>table.attribute</>
|
notations <literal>attribute(table)</> and <literal>table.attribute</>
|
||||||
interchangeably.
|
interchangeably.
|
||||||
@ -693,9 +694,14 @@ SELECT *, upper(fooname) FROM getfoo(1) AS t1;
|
|||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2>
|
<sect2 id="xfunc-sql-functions-returning-set">
|
||||||
<title><acronym>SQL</acronym> Functions Returning Sets</title>
|
<title><acronym>SQL</acronym> Functions Returning Sets</title>
|
||||||
|
|
||||||
|
<indexterm>
|
||||||
|
<primary>function</primary>
|
||||||
|
<secondary>with SETOF</secondary>
|
||||||
|
</indexterm>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
When an SQL function is declared as returning <literal>SETOF
|
When an SQL function is declared as returning <literal>SETOF
|
||||||
<replaceable>sometype</></literal>, the function's final
|
<replaceable>sometype</></literal>, the function's final
|
||||||
@ -733,7 +739,7 @@ SELECT * FROM getfoo(1) AS t1;
|
|||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
CREATE FUNCTION sum_n_product_with_tab (x int, OUT sum int, OUT product int) RETURNS SETOF record AS $$
|
CREATE FUNCTION sum_n_product_with_tab (x int, OUT sum int, OUT product int) RETURNS SETOF record AS $$
|
||||||
SELECT x + tab.y, x * tab.y FROM tab;
|
SELECT $1 + tab.y, $1 * tab.y FROM tab;
|
||||||
$$ LANGUAGE SQL;
|
$$ LANGUAGE SQL;
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
|
||||||
@ -794,6 +800,41 @@ SELECT name, listchildren(name) FROM nodes;
|
|||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
|
<sect2 id="xfunc-sql-functions-returning-table">
|
||||||
|
<title><acronym>SQL</acronym> Functions Returning <literal>TABLE</></title>
|
||||||
|
|
||||||
|
<indexterm>
|
||||||
|
<primary>function</primary>
|
||||||
|
<secondary>RETURNS TABLE</secondary>
|
||||||
|
</indexterm>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
There is another way to declare a function as returning a set,
|
||||||
|
which is to use the syntax
|
||||||
|
<literal>RETURNS TABLE(<replaceable>columns</>)</literal>.
|
||||||
|
This is equivalent to using one or more <literal>OUT</> parameters plus
|
||||||
|
marking the function as returning <literal>SETOF record</> (or
|
||||||
|
<literal>SETOF</> a single output parameter's type, as appropriate).
|
||||||
|
This notation is specified in recent versions of the SQL standard, and
|
||||||
|
thus may be more portable than using <literal>SETOF</>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
For example, the preceding sum-and-product example could also be
|
||||||
|
done this way:
|
||||||
|
|
||||||
|
<programlisting>
|
||||||
|
CREATE FUNCTION sum_n_product_with_tab (x int) RETURNS TABLE(sum int, product int) AS $$
|
||||||
|
SELECT $1 + tab.y, $1 * tab.y FROM tab;
|
||||||
|
$$ LANGUAGE SQL;
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
It is not allowed to use explicit <literal>OUT</> or <literal>INOUT</>
|
||||||
|
parameters with the <literal>RETURNS TABLE</> notation — you must
|
||||||
|
put all the output columns in the <literal>TABLE</> list.
|
||||||
|
</para>
|
||||||
|
</sect2>
|
||||||
|
|
||||||
<sect2>
|
<sect2>
|
||||||
<title>Polymorphic <acronym>SQL</acronym> Functions</title>
|
<title>Polymorphic <acronym>SQL</acronym> Functions</title>
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 2003-2008, PostgreSQL Global Development Group
|
* Copyright (c) 2003-2008, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/backend/catalog/information_schema.sql,v 1.44 2008/07/16 01:30:21 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/catalog/information_schema.sql,v 1.45 2008/07/18 03:32:52 tgl Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1007,6 +1007,7 @@ CREATE VIEW parameters AS
|
|||||||
WHEN proargmodes[(ss.x).n] = 'o' THEN 'OUT'
|
WHEN proargmodes[(ss.x).n] = 'o' THEN 'OUT'
|
||||||
WHEN proargmodes[(ss.x).n] = 'b' THEN 'INOUT'
|
WHEN proargmodes[(ss.x).n] = 'b' THEN 'INOUT'
|
||||||
WHEN proargmodes[(ss.x).n] = 'v' THEN 'IN'
|
WHEN proargmodes[(ss.x).n] = 'v' THEN 'IN'
|
||||||
|
WHEN proargmodes[(ss.x).n] = 't' THEN 'OUT'
|
||||||
END AS character_data) AS parameter_mode,
|
END AS character_data) AS parameter_mode,
|
||||||
CAST('NO' AS character_data) AS is_result,
|
CAST('NO' AS character_data) AS is_result,
|
||||||
CAST('NO' AS character_data) AS as_locator,
|
CAST('NO' AS character_data) AS as_locator,
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.152 2008/07/16 16:55:23 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.153 2008/07/18 03:32:52 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -242,6 +242,7 @@ ProcedureCreate(const char *procedureName,
|
|||||||
elog(ERROR, "variadic parameter must be last");
|
elog(ERROR, "variadic parameter must be last");
|
||||||
break;
|
break;
|
||||||
case PROARGMODE_OUT:
|
case PROARGMODE_OUT:
|
||||||
|
case PROARGMODE_TABLE:
|
||||||
/* okay */
|
/* okay */
|
||||||
break;
|
break;
|
||||||
case PROARGMODE_VARIADIC:
|
case PROARGMODE_VARIADIC:
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.97 2008/07/16 16:55:23 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.98 2008/07/18 03:32:52 tgl Exp $
|
||||||
*
|
*
|
||||||
* DESCRIPTION
|
* DESCRIPTION
|
||||||
* These routines take the parse tree and pick out the
|
* These routines take the parse tree and pick out the
|
||||||
@ -228,9 +228,10 @@ examine_parameter_list(List *parameters, Oid languageOid,
|
|||||||
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
||||||
errmsg("functions cannot accept set arguments")));
|
errmsg("functions cannot accept set arguments")));
|
||||||
|
|
||||||
if (fp->mode != FUNC_PARAM_OUT)
|
/* handle input parameters */
|
||||||
|
if (fp->mode != FUNC_PARAM_OUT && fp->mode != FUNC_PARAM_TABLE)
|
||||||
{
|
{
|
||||||
/* only OUT parameters can follow a VARIADIC parameter */
|
/* other input parameters can't follow a VARIADIC parameter */
|
||||||
if (varCount > 0)
|
if (varCount > 0)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
||||||
@ -238,9 +239,10 @@ examine_parameter_list(List *parameters, Oid languageOid,
|
|||||||
inTypes[inCount++] = toid;
|
inTypes[inCount++] = toid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* handle output parameters */
|
||||||
if (fp->mode != FUNC_PARAM_IN && fp->mode != FUNC_PARAM_VARIADIC)
|
if (fp->mode != FUNC_PARAM_IN && fp->mode != FUNC_PARAM_VARIADIC)
|
||||||
{
|
{
|
||||||
if (outCount == 0) /* save first OUT param's type */
|
if (outCount == 0) /* save first output param's type */
|
||||||
*requiredResultType = toid;
|
*requiredResultType = toid;
|
||||||
outCount++;
|
outCount++;
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.617 2008/07/16 01:30:22 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.618 2008/07/18 03:32:52 tgl Exp $
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
* AUTHOR DATE MAJOR EVENT
|
* AUTHOR DATE MAJOR EVENT
|
||||||
@ -112,6 +112,8 @@ static Node *doNegate(Node *n, int location);
|
|||||||
static void doNegateFloat(Value *v);
|
static void doNegateFloat(Value *v);
|
||||||
static Node *makeAArrayExpr(List *elements);
|
static Node *makeAArrayExpr(List *elements);
|
||||||
static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args);
|
static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args);
|
||||||
|
static List *mergeTableFuncParameters(List *func_args, List *columns);
|
||||||
|
static TypeName *TableFuncTypeName(List *columns);
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
@ -253,13 +255,13 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
|
|||||||
TableFuncElementList opt_type_modifiers
|
TableFuncElementList opt_type_modifiers
|
||||||
prep_type_clause
|
prep_type_clause
|
||||||
execute_param_clause using_clause returning_clause
|
execute_param_clause using_clause returning_clause
|
||||||
enum_val_list
|
enum_val_list table_func_column_list
|
||||||
|
|
||||||
%type <range> OptTempTableName
|
%type <range> OptTempTableName
|
||||||
%type <into> into_clause create_as_target
|
%type <into> into_clause create_as_target
|
||||||
|
|
||||||
%type <defelt> createfunc_opt_item common_func_opt_item
|
%type <defelt> createfunc_opt_item common_func_opt_item
|
||||||
%type <fun_param> func_arg
|
%type <fun_param> func_arg table_func_column
|
||||||
%type <fun_param_mode> arg_class
|
%type <fun_param_mode> arg_class
|
||||||
%type <typnam> func_return func_type
|
%type <typnam> func_return func_type
|
||||||
|
|
||||||
@ -4118,6 +4120,19 @@ CreateFunctionStmt:
|
|||||||
n->withClause = $9;
|
n->withClause = $9;
|
||||||
$$ = (Node *)n;
|
$$ = (Node *)n;
|
||||||
}
|
}
|
||||||
|
| CREATE opt_or_replace FUNCTION func_name func_args
|
||||||
|
RETURNS TABLE '(' table_func_column_list ')' createfunc_opt_list opt_definition
|
||||||
|
{
|
||||||
|
CreateFunctionStmt *n = makeNode(CreateFunctionStmt);
|
||||||
|
n->replace = $2;
|
||||||
|
n->funcname = $4;
|
||||||
|
n->parameters = mergeTableFuncParameters($5, $9);
|
||||||
|
n->returnType = TableFuncTypeName($9);
|
||||||
|
n->returnType->location = @7;
|
||||||
|
n->options = $11;
|
||||||
|
n->withClause = $12;
|
||||||
|
$$ = (Node *)n;
|
||||||
|
}
|
||||||
| CREATE opt_or_replace FUNCTION func_name func_args
|
| CREATE opt_or_replace FUNCTION func_name func_args
|
||||||
createfunc_opt_list opt_definition
|
createfunc_opt_list opt_definition
|
||||||
{
|
{
|
||||||
@ -4338,6 +4353,27 @@ opt_definition:
|
|||||||
| /*EMPTY*/ { $$ = NIL; }
|
| /*EMPTY*/ { $$ = NIL; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
table_func_column: param_name func_type
|
||||||
|
{
|
||||||
|
FunctionParameter *n = makeNode(FunctionParameter);
|
||||||
|
n->name = $1;
|
||||||
|
n->argType = $2;
|
||||||
|
n->mode = FUNC_PARAM_TABLE;
|
||||||
|
$$ = n;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
table_func_column_list:
|
||||||
|
table_func_column
|
||||||
|
{
|
||||||
|
$$ = list_make1($1);
|
||||||
|
}
|
||||||
|
| table_func_column_list ',' table_func_column
|
||||||
|
{
|
||||||
|
$$ = lappend($1, $3);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* ALTER FUNCTION
|
* ALTER FUNCTION
|
||||||
*
|
*
|
||||||
@ -9678,7 +9714,7 @@ extractArgTypes(List *parameters)
|
|||||||
{
|
{
|
||||||
FunctionParameter *p = (FunctionParameter *) lfirst(i);
|
FunctionParameter *p = (FunctionParameter *) lfirst(i);
|
||||||
|
|
||||||
if (p->mode != FUNC_PARAM_OUT) /* keep if IN, INOUT, VARIADIC */
|
if (p->mode != FUNC_PARAM_OUT && p->mode != FUNC_PARAM_TABLE)
|
||||||
result = lappend(result, p->argType);
|
result = lappend(result, p->argType);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -9861,6 +9897,51 @@ parser_init(void)
|
|||||||
QueryIsRule = FALSE;
|
QueryIsRule = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Merge the input and output parameters of a table function.
|
||||||
|
*/
|
||||||
|
static List *
|
||||||
|
mergeTableFuncParameters(List *func_args, List *columns)
|
||||||
|
{
|
||||||
|
ListCell *lc;
|
||||||
|
|
||||||
|
/* Explicit OUT and INOUT parameters shouldn't be used in this syntax */
|
||||||
|
foreach(lc, func_args)
|
||||||
|
{
|
||||||
|
FunctionParameter *p = (FunctionParameter *) lfirst(lc);
|
||||||
|
|
||||||
|
if (p->mode != FUNC_PARAM_IN && p->mode != FUNC_PARAM_VARIADIC)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||||
|
errmsg("OUT and INOUT arguments aren't allowed in TABLE functions")));
|
||||||
|
}
|
||||||
|
|
||||||
|
return list_concat(func_args, columns);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine return type of a TABLE function. A single result column
|
||||||
|
* returns setof that column's type; otherwise return setof record.
|
||||||
|
*/
|
||||||
|
static TypeName *
|
||||||
|
TableFuncTypeName(List *columns)
|
||||||
|
{
|
||||||
|
TypeName *result;
|
||||||
|
|
||||||
|
if (list_length(columns) == 1)
|
||||||
|
{
|
||||||
|
FunctionParameter *p = (FunctionParameter *) linitial(columns);
|
||||||
|
|
||||||
|
result = (TypeName *) copyObject(p->argType);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
result = SystemTypeName("record");
|
||||||
|
|
||||||
|
result->setof = true;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Must undefine base_yylex before including scan.c, since we want it
|
* Must undefine base_yylex before including scan.c, since we want it
|
||||||
* to create the function base_yylex not filtered_base_yylex.
|
* to create the function base_yylex not filtered_base_yylex.
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.277 2008/07/16 16:55:23 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.278 2008/07/18 03:32:52 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -135,6 +135,8 @@ static char *pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
|
|||||||
int prettyFlags);
|
int prettyFlags);
|
||||||
static char *pg_get_expr_worker(text *expr, Oid relid, char *relname,
|
static char *pg_get_expr_worker(text *expr, Oid relid, char *relname,
|
||||||
int prettyFlags);
|
int prettyFlags);
|
||||||
|
static int print_function_arguments(StringInfo buf, HeapTuple proctup,
|
||||||
|
bool print_table_args);
|
||||||
static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
|
static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
|
||||||
int prettyFlags);
|
int prettyFlags);
|
||||||
static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
|
static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
|
||||||
@ -1395,6 +1397,147 @@ pg_get_serial_sequence(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pg_get_function_arguments
|
||||||
|
* Get a nicely-formatted list of arguments for a function.
|
||||||
|
* This is everything that would go between the parentheses in
|
||||||
|
* CREATE FUNCTION.
|
||||||
|
*/
|
||||||
|
Datum
|
||||||
|
pg_get_function_arguments(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
Oid funcid = PG_GETARG_OID(0);
|
||||||
|
StringInfoData buf;
|
||||||
|
HeapTuple proctup;
|
||||||
|
|
||||||
|
initStringInfo(&buf);
|
||||||
|
|
||||||
|
proctup = SearchSysCache(PROCOID,
|
||||||
|
ObjectIdGetDatum(funcid),
|
||||||
|
0, 0, 0);
|
||||||
|
if (!HeapTupleIsValid(proctup))
|
||||||
|
elog(ERROR, "cache lookup failed for function %u", funcid);
|
||||||
|
|
||||||
|
(void) print_function_arguments(&buf, proctup, false);
|
||||||
|
|
||||||
|
ReleaseSysCache(proctup);
|
||||||
|
|
||||||
|
PG_RETURN_TEXT_P(string_to_text(buf.data));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pg_get_function_result
|
||||||
|
* Get a nicely-formatted version of the result type of a function.
|
||||||
|
* This is what would appear after RETURNS in CREATE FUNCTION.
|
||||||
|
*/
|
||||||
|
Datum
|
||||||
|
pg_get_function_result(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
Oid funcid = PG_GETARG_OID(0);
|
||||||
|
StringInfoData buf;
|
||||||
|
HeapTuple proctup;
|
||||||
|
Form_pg_proc procform;
|
||||||
|
int ntabargs = 0;
|
||||||
|
|
||||||
|
initStringInfo(&buf);
|
||||||
|
|
||||||
|
proctup = SearchSysCache(PROCOID,
|
||||||
|
ObjectIdGetDatum(funcid),
|
||||||
|
0, 0, 0);
|
||||||
|
if (!HeapTupleIsValid(proctup))
|
||||||
|
elog(ERROR, "cache lookup failed for function %u", funcid);
|
||||||
|
procform = (Form_pg_proc) GETSTRUCT(proctup);
|
||||||
|
|
||||||
|
if (procform->proretset)
|
||||||
|
{
|
||||||
|
/* It might be a table function; try to print the arguments */
|
||||||
|
appendStringInfoString(&buf, "TABLE(");
|
||||||
|
ntabargs = print_function_arguments(&buf, proctup, true);
|
||||||
|
if (ntabargs > 0)
|
||||||
|
appendStringInfoString(&buf, ")");
|
||||||
|
else
|
||||||
|
resetStringInfo(&buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ntabargs == 0)
|
||||||
|
{
|
||||||
|
/* Not a table function, so do the normal thing */
|
||||||
|
if (procform->proretset)
|
||||||
|
appendStringInfoString(&buf, "SETOF ");
|
||||||
|
appendStringInfoString(&buf, format_type_be(procform->prorettype));
|
||||||
|
}
|
||||||
|
|
||||||
|
ReleaseSysCache(proctup);
|
||||||
|
|
||||||
|
PG_RETURN_TEXT_P(string_to_text(buf.data));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Common code for pg_get_function_arguments and pg_get_function_result:
|
||||||
|
* append the desired subset of arguments to buf. We print only TABLE
|
||||||
|
* arguments when print_table_args is true, and all the others when it's false.
|
||||||
|
* Function return value is the number of arguments printed.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
print_function_arguments(StringInfo buf, HeapTuple proctup,
|
||||||
|
bool print_table_args)
|
||||||
|
{
|
||||||
|
int numargs;
|
||||||
|
Oid *argtypes;
|
||||||
|
char **argnames;
|
||||||
|
char *argmodes;
|
||||||
|
int argsprinted;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
numargs = get_func_arg_info(proctup,
|
||||||
|
&argtypes, &argnames, &argmodes);
|
||||||
|
|
||||||
|
argsprinted = 0;
|
||||||
|
for (i = 0; i < numargs; i++)
|
||||||
|
{
|
||||||
|
Oid argtype = argtypes[i];
|
||||||
|
char *argname = argnames ? argnames[i] : NULL;
|
||||||
|
char argmode = argmodes ? argmodes[i] : PROARGMODE_IN;
|
||||||
|
const char *modename;
|
||||||
|
|
||||||
|
if (print_table_args != (argmode == PROARGMODE_TABLE))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch (argmode)
|
||||||
|
{
|
||||||
|
case PROARGMODE_IN:
|
||||||
|
modename = "";
|
||||||
|
break;
|
||||||
|
case PROARGMODE_INOUT:
|
||||||
|
modename = "INOUT ";
|
||||||
|
break;
|
||||||
|
case PROARGMODE_OUT:
|
||||||
|
modename = "OUT ";
|
||||||
|
break;
|
||||||
|
case PROARGMODE_VARIADIC:
|
||||||
|
modename = "VARIADIC ";
|
||||||
|
break;
|
||||||
|
case PROARGMODE_TABLE:
|
||||||
|
modename = "";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
elog(ERROR, "invalid parameter mode '%c'", argmode);
|
||||||
|
modename = NULL; /* keep compiler quiet */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (argsprinted)
|
||||||
|
appendStringInfoString(buf, ", ");
|
||||||
|
appendStringInfoString(buf, modename);
|
||||||
|
if (argname && argname[0])
|
||||||
|
appendStringInfo(buf, "%s ", argname);
|
||||||
|
appendStringInfoString(buf, format_type_be(argtype));
|
||||||
|
argsprinted++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return argsprinted;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* deparse_expression - General utility for deparsing expressions
|
* deparse_expression - General utility for deparsing expressions
|
||||||
*
|
*
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Copyright (c) 2002-2008, PostgreSQL Global Development Group
|
* Copyright (c) 2002-2008, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/fmgr/funcapi.c,v 1.40 2008/07/16 01:30:22 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/fmgr/funcapi.c,v 1.41 2008/07/18 03:32:52 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -550,7 +550,7 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
|
|||||||
case ANYELEMENTOID:
|
case ANYELEMENTOID:
|
||||||
case ANYNONARRAYOID:
|
case ANYNONARRAYOID:
|
||||||
case ANYENUMOID:
|
case ANYENUMOID:
|
||||||
if (argmode == PROARGMODE_OUT)
|
if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
|
||||||
have_anyelement_result = true;
|
have_anyelement_result = true;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -565,7 +565,7 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ANYARRAYOID:
|
case ANYARRAYOID:
|
||||||
if (argmode == PROARGMODE_OUT)
|
if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
|
||||||
have_anyarray_result = true;
|
have_anyarray_result = true;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -582,7 +582,7 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (argmode != PROARGMODE_OUT)
|
if (argmode != PROARGMODE_OUT && argmode != PROARGMODE_TABLE)
|
||||||
inargno++;
|
inargno++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -848,7 +848,8 @@ get_func_result_name(Oid functionId)
|
|||||||
argmodes[i] == PROARGMODE_VARIADIC)
|
argmodes[i] == PROARGMODE_VARIADIC)
|
||||||
continue;
|
continue;
|
||||||
Assert(argmodes[i] == PROARGMODE_OUT ||
|
Assert(argmodes[i] == PROARGMODE_OUT ||
|
||||||
argmodes[i] == PROARGMODE_INOUT);
|
argmodes[i] == PROARGMODE_INOUT ||
|
||||||
|
argmodes[i] == PROARGMODE_TABLE);
|
||||||
if (++numoutargs > 1)
|
if (++numoutargs > 1)
|
||||||
{
|
{
|
||||||
/* multiple out args, so forget it */
|
/* multiple out args, so forget it */
|
||||||
@ -999,7 +1000,8 @@ build_function_result_tupdesc_d(Datum proallargtypes,
|
|||||||
argmodes[i] == PROARGMODE_VARIADIC)
|
argmodes[i] == PROARGMODE_VARIADIC)
|
||||||
continue;
|
continue;
|
||||||
Assert(argmodes[i] == PROARGMODE_OUT ||
|
Assert(argmodes[i] == PROARGMODE_OUT ||
|
||||||
argmodes[i] == PROARGMODE_INOUT);
|
argmodes[i] == PROARGMODE_INOUT ||
|
||||||
|
argmodes[i] == PROARGMODE_TABLE);
|
||||||
outargtypes[numoutargs] = argtypes[i];
|
outargtypes[numoutargs] = argtypes[i];
|
||||||
if (argnames)
|
if (argnames)
|
||||||
pname = TextDatumGetCString(argnames[i]);
|
pname = TextDatumGetCString(argnames[i]);
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
* by PostgreSQL
|
* by PostgreSQL
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.495 2008/07/16 16:55:23 tgl Exp $
|
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.496 2008/07/18 03:32:52 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -165,7 +165,8 @@ static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
|
|||||||
static void getDependencies(void);
|
static void getDependencies(void);
|
||||||
static void getDomainConstraints(TypeInfo *tinfo);
|
static void getDomainConstraints(TypeInfo *tinfo);
|
||||||
static void getTableData(TableInfo *tblinfo, int numTables, bool oids);
|
static void getTableData(TableInfo *tblinfo, int numTables, bool oids);
|
||||||
static char *format_function_arguments(FuncInfo *finfo, int nallargs,
|
static char *format_function_arguments(FuncInfo *finfo, char *funcargs);
|
||||||
|
static char *format_function_arguments_old(FuncInfo *finfo, int nallargs,
|
||||||
char **allargtypes,
|
char **allargtypes,
|
||||||
char **argmodes,
|
char **argmodes,
|
||||||
char **argnames);
|
char **argnames);
|
||||||
@ -6405,16 +6406,34 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang)
|
|||||||
/*
|
/*
|
||||||
* format_function_arguments: generate function name and argument list
|
* format_function_arguments: generate function name and argument list
|
||||||
*
|
*
|
||||||
|
* This is used when we can rely on pg_get_function_arguments to format
|
||||||
|
* the argument list.
|
||||||
|
*/
|
||||||
|
static char *format_function_arguments(FuncInfo *finfo, char *funcargs)
|
||||||
|
{
|
||||||
|
PQExpBufferData fn;
|
||||||
|
|
||||||
|
initPQExpBuffer(&fn);
|
||||||
|
appendPQExpBuffer(&fn, "%s(%s)", fmtId(finfo->dobj.name), funcargs);
|
||||||
|
return fn.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* format_function_arguments_old: generate function name and argument list
|
||||||
|
*
|
||||||
* The argument type names are qualified if needed. The function name
|
* The argument type names are qualified if needed. The function name
|
||||||
* is never qualified.
|
* is never qualified.
|
||||||
*
|
*
|
||||||
|
* This is used only with pre-8.4 servers, so we aren't expecting to see
|
||||||
|
* VARIADIC or TABLE arguments.
|
||||||
|
*
|
||||||
* Any or all of allargtypes, argmodes, argnames may be NULL.
|
* Any or all of allargtypes, argmodes, argnames may be NULL.
|
||||||
*/
|
*/
|
||||||
static char *
|
static char *
|
||||||
format_function_arguments(FuncInfo *finfo, int nallargs,
|
format_function_arguments_old(FuncInfo *finfo, int nallargs,
|
||||||
char **allargtypes,
|
char **allargtypes,
|
||||||
char **argmodes,
|
char **argmodes,
|
||||||
char **argnames)
|
char **argnames)
|
||||||
{
|
{
|
||||||
PQExpBufferData fn;
|
PQExpBufferData fn;
|
||||||
int j;
|
int j;
|
||||||
@ -6444,9 +6463,6 @@ format_function_arguments(FuncInfo *finfo, int nallargs,
|
|||||||
case PROARGMODE_INOUT:
|
case PROARGMODE_INOUT:
|
||||||
argmode = "INOUT ";
|
argmode = "INOUT ";
|
||||||
break;
|
break;
|
||||||
case PROARGMODE_VARIADIC:
|
|
||||||
argmode = "VARIADIC ";
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
|
write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
|
||||||
argmode = "";
|
argmode = "";
|
||||||
@ -6475,7 +6491,7 @@ format_function_arguments(FuncInfo *finfo, int nallargs,
|
|||||||
/*
|
/*
|
||||||
* format_function_signature: generate function name and argument list
|
* format_function_signature: generate function name and argument list
|
||||||
*
|
*
|
||||||
* This is like format_function_arguments except that only a minimal
|
* This is like format_function_arguments_old except that only a minimal
|
||||||
* list of input argument types is generated; this is sufficient to
|
* list of input argument types is generated; this is sufficient to
|
||||||
* reference the function, but not to define it.
|
* reference the function, but not to define it.
|
||||||
*
|
*
|
||||||
@ -6527,6 +6543,8 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
|
|||||||
char *proretset;
|
char *proretset;
|
||||||
char *prosrc;
|
char *prosrc;
|
||||||
char *probin;
|
char *probin;
|
||||||
|
char *funcargs;
|
||||||
|
char *funcresult;
|
||||||
char *proallargtypes;
|
char *proallargtypes;
|
||||||
char *proargmodes;
|
char *proargmodes;
|
||||||
char *proargnames;
|
char *proargnames;
|
||||||
@ -6559,7 +6577,24 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
|
|||||||
selectSourceSchema(finfo->dobj.namespace->dobj.name);
|
selectSourceSchema(finfo->dobj.namespace->dobj.name);
|
||||||
|
|
||||||
/* Fetch function-specific details */
|
/* Fetch function-specific details */
|
||||||
if (g_fout->remoteVersion >= 80300)
|
if (g_fout->remoteVersion >= 80400)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* In 8.4 and up we rely on pg_get_function_arguments and
|
||||||
|
* pg_get_function_result instead of examining proallargtypes etc.
|
||||||
|
*/
|
||||||
|
appendPQExpBuffer(query,
|
||||||
|
"SELECT proretset, prosrc, probin, "
|
||||||
|
"pg_catalog.pg_get_function_arguments(oid) as funcargs, "
|
||||||
|
"pg_catalog.pg_get_function_result(oid) as funcresult, "
|
||||||
|
"provolatile, proisstrict, prosecdef, "
|
||||||
|
"proconfig, procost, prorows, "
|
||||||
|
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
|
||||||
|
"FROM pg_catalog.pg_proc "
|
||||||
|
"WHERE oid = '%u'::pg_catalog.oid",
|
||||||
|
finfo->dobj.catId.oid);
|
||||||
|
}
|
||||||
|
else if (g_fout->remoteVersion >= 80300)
|
||||||
{
|
{
|
||||||
appendPQExpBuffer(query,
|
appendPQExpBuffer(query,
|
||||||
"SELECT proretset, prosrc, probin, "
|
"SELECT proretset, prosrc, probin, "
|
||||||
@ -6659,9 +6694,19 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
|
|||||||
proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
|
proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
|
||||||
prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
|
prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
|
||||||
probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
|
probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
|
||||||
proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
|
if (g_fout->remoteVersion >= 80400)
|
||||||
proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
|
{
|
||||||
proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
|
funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
|
||||||
|
funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
|
||||||
|
proallargtypes = proargmodes = proargnames = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
|
||||||
|
proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
|
||||||
|
proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
|
||||||
|
funcargs = funcresult = NULL;
|
||||||
|
}
|
||||||
provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
|
provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
|
||||||
proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
|
proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
|
||||||
prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
|
prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
|
||||||
@ -6766,8 +6811,11 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
funcsig = format_function_arguments(finfo, nallargs, allargtypes,
|
if (funcargs)
|
||||||
argmodes, argnames);
|
funcsig = format_function_arguments(finfo, funcargs);
|
||||||
|
else
|
||||||
|
funcsig = format_function_arguments_old(finfo, nallargs, allargtypes,
|
||||||
|
argmodes, argnames);
|
||||||
funcsig_tag = format_function_signature(finfo, false);
|
funcsig_tag = format_function_signature(finfo, false);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -6777,13 +6825,17 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
|
|||||||
fmtId(finfo->dobj.namespace->dobj.name),
|
fmtId(finfo->dobj.namespace->dobj.name),
|
||||||
funcsig);
|
funcsig);
|
||||||
|
|
||||||
rettypename = getFormattedTypeName(finfo->prorettype, zeroAsOpaque);
|
|
||||||
|
|
||||||
appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcsig);
|
appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcsig);
|
||||||
appendPQExpBuffer(q, "RETURNS %s%s",
|
if (funcresult)
|
||||||
(proretset[0] == 't') ? "SETOF " : "",
|
appendPQExpBuffer(q, "RETURNS %s", funcresult);
|
||||||
rettypename);
|
else
|
||||||
free(rettypename);
|
{
|
||||||
|
rettypename = getFormattedTypeName(finfo->prorettype, zeroAsOpaque);
|
||||||
|
appendPQExpBuffer(q, "RETURNS %s%s",
|
||||||
|
(proretset[0] == 't') ? "SETOF " : "",
|
||||||
|
rettypename);
|
||||||
|
free(rettypename);
|
||||||
|
}
|
||||||
|
|
||||||
appendPQExpBuffer(q, "\n LANGUAGE %s", fmtId(lanname));
|
appendPQExpBuffer(q, "\n LANGUAGE %s", fmtId(lanname));
|
||||||
if (provolatile[0] != PROVOLATILE_VOLATILE)
|
if (provolatile[0] != PROVOLATILE_VOLATILE)
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 2000-2008, PostgreSQL Global Development Group
|
* Copyright (c) 2000-2008, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.182 2008/07/16 01:30:23 tgl Exp $
|
* $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.183 2008/07/18 03:32:52 tgl Exp $
|
||||||
*/
|
*/
|
||||||
#include "postgres_fe.h"
|
#include "postgres_fe.h"
|
||||||
|
|
||||||
@ -189,15 +189,20 @@ describeFunctions(const char *pattern, bool verbose)
|
|||||||
|
|
||||||
printfPQExpBuffer(&buf,
|
printfPQExpBuffer(&buf,
|
||||||
"SELECT n.nspname as \"%s\",\n"
|
"SELECT n.nspname as \"%s\",\n"
|
||||||
" p.proname as \"%s\",\n"
|
" p.proname as \"%s\",\n",
|
||||||
" CASE WHEN p.proretset THEN 'setof ' ELSE '' END ||\n"
|
|
||||||
" pg_catalog.format_type(p.prorettype, NULL) as \"%s\",\n",
|
|
||||||
gettext_noop("Schema"),
|
gettext_noop("Schema"),
|
||||||
gettext_noop("Name"),
|
gettext_noop("Name"));
|
||||||
gettext_noop("Result data type"));
|
|
||||||
|
|
||||||
if (pset.sversion >= 80100)
|
if (pset.sversion >= 80400)
|
||||||
appendPQExpBuffer(&buf,
|
appendPQExpBuffer(&buf,
|
||||||
|
" pg_catalog.pg_get_function_result(p.oid) as \"%s\",\n"
|
||||||
|
" pg_catalog.pg_get_function_arguments(p.oid) as \"%s\"",
|
||||||
|
gettext_noop("Result data type"),
|
||||||
|
gettext_noop("Argument data types"));
|
||||||
|
else if (pset.sversion >= 80100)
|
||||||
|
appendPQExpBuffer(&buf,
|
||||||
|
" CASE WHEN p.proretset THEN 'SETOF ' ELSE '' END ||\n"
|
||||||
|
" pg_catalog.format_type(p.prorettype, NULL) as \"%s\",\n"
|
||||||
" CASE WHEN proallargtypes IS NOT NULL THEN\n"
|
" CASE WHEN proallargtypes IS NOT NULL THEN\n"
|
||||||
" pg_catalog.array_to_string(ARRAY(\n"
|
" pg_catalog.array_to_string(ARRAY(\n"
|
||||||
" SELECT\n"
|
" SELECT\n"
|
||||||
@ -227,10 +232,14 @@ describeFunctions(const char *pattern, bool verbose)
|
|||||||
" pg_catalog.generate_series(0, pg_catalog.array_upper(p.proargtypes, 1)) AS s(i)\n"
|
" pg_catalog.generate_series(0, pg_catalog.array_upper(p.proargtypes, 1)) AS s(i)\n"
|
||||||
" ), ', ')\n"
|
" ), ', ')\n"
|
||||||
" END AS \"%s\"",
|
" END AS \"%s\"",
|
||||||
gettext_noop("Argument data types"));
|
gettext_noop("Result data type"),
|
||||||
|
gettext_noop("Argument data types"));
|
||||||
else
|
else
|
||||||
appendPQExpBuffer(&buf,
|
appendPQExpBuffer(&buf,
|
||||||
|
" CASE WHEN p.proretset THEN 'SETOF ' ELSE '' END ||\n"
|
||||||
|
" pg_catalog.format_type(p.prorettype, NULL) as \"%s\",\n"
|
||||||
" pg_catalog.oidvectortypes(p.proargtypes) as \"%s\"",
|
" pg_catalog.oidvectortypes(p.proargtypes) as \"%s\"",
|
||||||
|
gettext_noop("Result data type"),
|
||||||
gettext_noop("Argument data types"));
|
gettext_noop("Argument data types"));
|
||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.470 2008/07/16 16:55:23 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.471 2008/07/18 03:32:52 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -53,6 +53,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* yyyymmddN */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 200807161
|
#define CATALOG_VERSION_NO 200807171
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.508 2008/07/16 16:55:24 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.509 2008/07/18 03:32:53 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* The script catalog/genbki.sh reads this file and generates .bki
|
* The script catalog/genbki.sh reads this file and generates .bki
|
||||||
@ -2291,6 +2291,10 @@ DATA(insert OID = 1716 ( pg_get_expr PGNSP PGUID 12 1 0 0 f f t f s 2 25 "2
|
|||||||
DESCR("deparse an encoded expression");
|
DESCR("deparse an encoded expression");
|
||||||
DATA(insert OID = 1665 ( pg_get_serial_sequence PGNSP PGUID 12 1 0 0 f f t f s 2 25 "25 25" _null_ _null_ _null_ pg_get_serial_sequence _null_ _null_ _null_ ));
|
DATA(insert OID = 1665 ( pg_get_serial_sequence PGNSP PGUID 12 1 0 0 f f t f s 2 25 "25 25" _null_ _null_ _null_ pg_get_serial_sequence _null_ _null_ _null_ ));
|
||||||
DESCR("name of sequence for a serial column");
|
DESCR("name of sequence for a serial column");
|
||||||
|
DATA(insert OID = 2162 ( pg_get_function_arguments PGNSP PGUID 12 1 0 0 f f t f s 1 25 "26" _null_ _null_ _null_ pg_get_function_arguments _null_ _null_ _null_ ));
|
||||||
|
DESCR("argument list of a function");
|
||||||
|
DATA(insert OID = 2165 ( pg_get_function_result PGNSP PGUID 12 1 0 0 f f t f s 1 25 "26" _null_ _null_ _null_ pg_get_function_result _null_ _null_ _null_ ));
|
||||||
|
DESCR("result type of a function");
|
||||||
|
|
||||||
DATA(insert OID = 1686 ( pg_get_keywords PGNSP PGUID 12 10 400 0 f f t t s 0 2249 "" "{25,18,25}" "{o,o,o}" "{word,catcode,catdesc}" pg_get_keywords _null_ _null_ _null_ ));
|
DATA(insert OID = 1686 ( pg_get_keywords PGNSP PGUID 12 10 400 0 f f t t s 0 2249 "" "{25,18,25}" "{o,o,o}" "{word,catcode,catdesc}" pg_get_keywords _null_ _null_ _null_ ));
|
||||||
DESCR("list of SQL keywords");
|
DESCR("list of SQL keywords");
|
||||||
@ -4477,5 +4481,6 @@ DESCR("is txid visible in snapshot?");
|
|||||||
#define PROARGMODE_OUT 'o'
|
#define PROARGMODE_OUT 'o'
|
||||||
#define PROARGMODE_INOUT 'b'
|
#define PROARGMODE_INOUT 'b'
|
||||||
#define PROARGMODE_VARIADIC 'v'
|
#define PROARGMODE_VARIADIC 'v'
|
||||||
|
#define PROARGMODE_TABLE 't'
|
||||||
|
|
||||||
#endif /* PG_PROC_H */
|
#endif /* PG_PROC_H */
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.367 2008/07/16 01:30:23 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.368 2008/07/18 03:32:53 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -1570,7 +1570,8 @@ typedef enum FunctionParameterMode
|
|||||||
FUNC_PARAM_IN = 'i', /* input only */
|
FUNC_PARAM_IN = 'i', /* input only */
|
||||||
FUNC_PARAM_OUT = 'o', /* output only */
|
FUNC_PARAM_OUT = 'o', /* output only */
|
||||||
FUNC_PARAM_INOUT = 'b', /* both */
|
FUNC_PARAM_INOUT = 'b', /* both */
|
||||||
FUNC_PARAM_VARIADIC = 'v' /* variadic */
|
FUNC_PARAM_VARIADIC = 'v', /* variadic */
|
||||||
|
FUNC_PARAM_TABLE = 't' /* table function output column */
|
||||||
} FunctionParameterMode;
|
} FunctionParameterMode;
|
||||||
|
|
||||||
typedef struct FunctionParameter
|
typedef struct FunctionParameter
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.318 2008/07/03 20:58:47 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.319 2008/07/18 03:32:53 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -551,6 +551,8 @@ extern Datum pg_get_expr(PG_FUNCTION_ARGS);
|
|||||||
extern Datum pg_get_expr_ext(PG_FUNCTION_ARGS);
|
extern Datum pg_get_expr_ext(PG_FUNCTION_ARGS);
|
||||||
extern Datum pg_get_userbyid(PG_FUNCTION_ARGS);
|
extern Datum pg_get_userbyid(PG_FUNCTION_ARGS);
|
||||||
extern Datum pg_get_serial_sequence(PG_FUNCTION_ARGS);
|
extern Datum pg_get_serial_sequence(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum pg_get_function_arguments(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum pg_get_function_result(PG_FUNCTION_ARGS);
|
||||||
extern char *deparse_expression(Node *expr, List *dpcontext,
|
extern char *deparse_expression(Node *expr, List *dpcontext,
|
||||||
bool forceprefix, bool showimplicit);
|
bool forceprefix, bool showimplicit);
|
||||||
extern List *deparse_context_for(const char *aliasname, Oid relid);
|
extern List *deparse_context_for(const char *aliasname, Oid relid);
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.127 2008/07/16 01:30:23 tgl Exp $
|
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.128 2008/07/18 03:32:53 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -441,7 +441,9 @@ do_compile(FunctionCallInfo fcinfo,
|
|||||||
argmode == PROARGMODE_INOUT ||
|
argmode == PROARGMODE_INOUT ||
|
||||||
argmode == PROARGMODE_VARIADIC)
|
argmode == PROARGMODE_VARIADIC)
|
||||||
in_arg_varnos[num_in_args++] = argvariable->dno;
|
in_arg_varnos[num_in_args++] = argvariable->dno;
|
||||||
if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_INOUT)
|
if (argmode == PROARGMODE_OUT ||
|
||||||
|
argmode == PROARGMODE_INOUT ||
|
||||||
|
argmode == PROARGMODE_TABLE)
|
||||||
out_arg_variables[num_out_args++] = argvariable;
|
out_arg_variables[num_out_args++] = argvariable;
|
||||||
|
|
||||||
/* Add to namespace under the $n name */
|
/* Add to namespace under the $n name */
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
* plpython.c - python as a procedural language for PostgreSQL
|
* plpython.c - python as a procedural language for PostgreSQL
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.111 2008/07/16 01:30:23 tgl Exp $
|
* $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.112 2008/07/18 03:32:53 tgl Exp $
|
||||||
*
|
*
|
||||||
*********************************************************************
|
*********************************************************************
|
||||||
*/
|
*/
|
||||||
@ -1271,7 +1271,8 @@ PLy_procedure_create(HeapTuple procTup, Oid tgreloid, char *key)
|
|||||||
/* proc->nargs was initialized to 0 above */
|
/* proc->nargs was initialized to 0 above */
|
||||||
for (i = 0; i < total; i++)
|
for (i = 0; i < total; i++)
|
||||||
{
|
{
|
||||||
if (modes[i] != PROARGMODE_OUT)
|
if (modes[i] != PROARGMODE_OUT &&
|
||||||
|
modes[i] != PROARGMODE_TABLE)
|
||||||
(proc->nargs)++;
|
(proc->nargs)++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1282,7 +1283,9 @@ PLy_procedure_create(HeapTuple procTup, Oid tgreloid, char *key)
|
|||||||
HeapTuple argTypeTup;
|
HeapTuple argTypeTup;
|
||||||
Form_pg_type argTypeStruct;
|
Form_pg_type argTypeStruct;
|
||||||
|
|
||||||
if (modes && modes[i] == PROARGMODE_OUT)
|
if (modes &&
|
||||||
|
(modes[i] == PROARGMODE_OUT ||
|
||||||
|
modes[i] == PROARGMODE_TABLE))
|
||||||
continue; /* skip OUT arguments */
|
continue; /* skip OUT arguments */
|
||||||
|
|
||||||
Assert(types[i] == procStruct->proargtypes.values[pos]);
|
Assert(types[i] == procStruct->proargtypes.values[pos]);
|
||||||
|
@ -3634,3 +3634,35 @@ NOTICE: non-variadic function called
|
|||||||
|
|
||||||
drop function pleast(numeric[]);
|
drop function pleast(numeric[]);
|
||||||
drop function pleast(numeric);
|
drop function pleast(numeric);
|
||||||
|
-- test table functions
|
||||||
|
create function tftest(int) returns table(a int, b int) as $$
|
||||||
|
begin
|
||||||
|
return query select $1, $1+i from generate_series(1,5) g(i);
|
||||||
|
end;
|
||||||
|
$$ language plpgsql immutable strict;
|
||||||
|
select * from tftest(10);
|
||||||
|
a | b
|
||||||
|
----+----
|
||||||
|
10 | 11
|
||||||
|
10 | 12
|
||||||
|
10 | 13
|
||||||
|
10 | 14
|
||||||
|
10 | 15
|
||||||
|
(5 rows)
|
||||||
|
|
||||||
|
create or replace function tftest(a1 int) returns table(a int, b int) as $$
|
||||||
|
begin
|
||||||
|
a := a1; b := a1 + 1;
|
||||||
|
return next;
|
||||||
|
a := a1 * 10; b := a1 * 10 + 1;
|
||||||
|
return next;
|
||||||
|
end;
|
||||||
|
$$ language plpgsql immutable strict;
|
||||||
|
select * from tftest(10);
|
||||||
|
a | b
|
||||||
|
-----+-----
|
||||||
|
10 | 11
|
||||||
|
100 | 101
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
drop function tftest(int);
|
||||||
|
@ -528,3 +528,40 @@ CREATE FUNCTION bad (f1 int, out f2 anyelement, out f3 anyarray)
|
|||||||
AS 'select $1, array[$1,$1]' LANGUAGE sql;
|
AS 'select $1, array[$1,$1]' LANGUAGE sql;
|
||||||
ERROR: cannot determine result data type
|
ERROR: cannot determine result data type
|
||||||
DETAIL: A function returning a polymorphic type must have at least one polymorphic argument.
|
DETAIL: A function returning a polymorphic type must have at least one polymorphic argument.
|
||||||
|
--
|
||||||
|
-- table functions
|
||||||
|
--
|
||||||
|
CREATE OR REPLACE FUNCTION foo()
|
||||||
|
RETURNS TABLE(a int)
|
||||||
|
AS $$ SELECT a FROM generate_series(1,5) a(a) $$ LANGUAGE sql;
|
||||||
|
SELECT * FROM foo();
|
||||||
|
a
|
||||||
|
---
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
5
|
||||||
|
(5 rows)
|
||||||
|
|
||||||
|
DROP FUNCTION foo();
|
||||||
|
CREATE OR REPLACE FUNCTION foo(int)
|
||||||
|
RETURNS TABLE(a int, b int)
|
||||||
|
AS $$ SELECT a, b
|
||||||
|
FROM generate_series(1,$1) a(a),
|
||||||
|
generate_series(1,$1) b(b) $$ LANGUAGE sql;
|
||||||
|
SELECT * FROM foo(3);
|
||||||
|
a | b
|
||||||
|
---+---
|
||||||
|
1 | 1
|
||||||
|
1 | 2
|
||||||
|
1 | 3
|
||||||
|
2 | 1
|
||||||
|
2 | 2
|
||||||
|
2 | 3
|
||||||
|
3 | 1
|
||||||
|
3 | 2
|
||||||
|
3 | 3
|
||||||
|
(9 rows)
|
||||||
|
|
||||||
|
DROP FUNCTION foo(int);
|
||||||
|
@ -2925,3 +2925,26 @@ select pleast(10);
|
|||||||
|
|
||||||
drop function pleast(numeric[]);
|
drop function pleast(numeric[]);
|
||||||
drop function pleast(numeric);
|
drop function pleast(numeric);
|
||||||
|
|
||||||
|
-- test table functions
|
||||||
|
|
||||||
|
create function tftest(int) returns table(a int, b int) as $$
|
||||||
|
begin
|
||||||
|
return query select $1, $1+i from generate_series(1,5) g(i);
|
||||||
|
end;
|
||||||
|
$$ language plpgsql immutable strict;
|
||||||
|
|
||||||
|
select * from tftest(10);
|
||||||
|
|
||||||
|
create or replace function tftest(a1 int) returns table(a int, b int) as $$
|
||||||
|
begin
|
||||||
|
a := a1; b := a1 + 1;
|
||||||
|
return next;
|
||||||
|
a := a1 * 10; b := a1 * 10 + 1;
|
||||||
|
return next;
|
||||||
|
end;
|
||||||
|
$$ language plpgsql immutable strict;
|
||||||
|
|
||||||
|
select * from tftest(10);
|
||||||
|
|
||||||
|
drop function tftest(int);
|
||||||
|
@ -261,3 +261,21 @@ DROP FUNCTION dup(anyelement);
|
|||||||
-- fails, no way to deduce outputs
|
-- fails, no way to deduce outputs
|
||||||
CREATE FUNCTION bad (f1 int, out f2 anyelement, out f3 anyarray)
|
CREATE FUNCTION bad (f1 int, out f2 anyelement, out f3 anyarray)
|
||||||
AS 'select $1, array[$1,$1]' LANGUAGE sql;
|
AS 'select $1, array[$1,$1]' LANGUAGE sql;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- table functions
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION foo()
|
||||||
|
RETURNS TABLE(a int)
|
||||||
|
AS $$ SELECT a FROM generate_series(1,5) a(a) $$ LANGUAGE sql;
|
||||||
|
SELECT * FROM foo();
|
||||||
|
DROP FUNCTION foo();
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION foo(int)
|
||||||
|
RETURNS TABLE(a int, b int)
|
||||||
|
AS $$ SELECT a, b
|
||||||
|
FROM generate_series(1,$1) a(a),
|
||||||
|
generate_series(1,$1) b(b) $$ LANGUAGE sql;
|
||||||
|
SELECT * FROM foo(3);
|
||||||
|
DROP FUNCTION foo(int);
|
||||||
|
Reference in New Issue
Block a user