1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-30 11:03:19 +03:00

Allow SQL-language functions to reference parameters by name.

Matthew Draper, reviewed by Hitoshi Harada
This commit is contained in:
Tom Lane
2012-02-04 19:23:49 -05:00
parent 342b83fdca
commit 9bff0780cf
6 changed files with 411 additions and 67 deletions

View File

@ -154,14 +154,50 @@ SELECT clean_emp();
the function (see <xref linkend="sql-syntax-strings">).
</para>
<para>
Arguments to the SQL function are referenced in the function
body using the syntax <literal>$<replaceable>n</></>: <literal>$1</>
refers to the first argument, <literal>$2</> to the second, and so on.
If an argument is of a composite type, then the dot notation,
e.g., <literal>$1.name</literal>, can be used to access attributes
of the argument. The arguments can only be used as data values,
not as identifiers. Thus for example this is reasonable:
<sect2 id="xfunc-sql-function-arguments">
<title>Arguments for <acronym>SQL</acronym> Functions</title>
<indexterm>
<primary>function</primary>
<secondary>named argument</secondary>
</indexterm>
<para>
Arguments of a SQL function can be referenced in the function
body using either names or numbers. Examples of both methods appear
below.
</para>
<para>
To use a name, declare the function argument as having a name, and
then just write that name in the function body. If the argument name
is the same as any column name in the current SQL command within the
function, the column name will take precedence. To override this,
qualify the argument name with the name of the function itself, that is
<literal><replaceable>function_name</>.<replaceable>argument_name</></literal>.
(If this would conflict with a qualified column name, again the column
name wins. You can avoid the ambiguity by choosing a different alias for
the table within the SQL command.)
</para>
<para>
In the older numeric approach, arguments are referenced using the syntax
<literal>$<replaceable>n</></>: <literal>$1</> refers to the first input
argument, <literal>$2</> to the second, and so on. This will work
whether or not the particular argument was declared with a name.
</para>
<para>
If an argument is of a composite type, then the dot notation,
e.g., <literal>argname.fieldname</literal> or
<literal>$1.fieldname</literal>, can be used to access attributes of the
argument. Again, you might need to qualify the argument's name with the
function name to make the form with an argument name unambiguous.
</para>
<para>
SQL function arguments can only be used as data values,
not as identifiers. Thus for example this is reasonable:
<programlisting>
INSERT INTO mytable VALUES ($1);
</programlisting>
@ -169,7 +205,16 @@ but this will not work:
<programlisting>
INSERT INTO $1 VALUES (42);
</programlisting>
</para>
</para>
<note>
<para>
The ability to use names to reference SQL function arguments was added
in <productname>PostgreSQL</productname> 9.2. Functions to be used in
older servers must use the <literal>$<replaceable>n</></> notation.
</para>
</note>
</sect2>
<sect2 id="xfunc-sql-base-functions">
<title><acronym>SQL</acronym> Functions on Base Types</title>
@ -205,9 +250,24 @@ SELECT one();
<para>
It is almost as easy to define <acronym>SQL</acronym> functions
that take base types as arguments. In the example below, notice
how we refer to the arguments within the function as <literal>$1</>
and <literal>$2</>.
that take base types as arguments:
<screen>
CREATE FUNCTION add_em(x integer, y integer) RETURNS integer AS $$
SELECT x + y;
$$ LANGUAGE SQL;
SELECT add_em(1, 2) AS answer;
answer
--------
3
</screen>
</para>
<para>
Alternatively, we could dispense with names for the arguments and
use numbers:
<screen>
CREATE FUNCTION add_em(integer, integer) RETURNS integer AS $$
@ -227,10 +287,10 @@ SELECT add_em(1, 2) AS answer;
bank account:
<programlisting>
CREATE FUNCTION tf1 (integer, numeric) RETURNS integer AS $$
CREATE FUNCTION tf1 (accountno integer, debit numeric) RETURNS integer AS $$
UPDATE bank
SET balance = balance - $2
WHERE accountno = $1;
SET balance = balance - debit
WHERE accountno = tf1.accountno;
SELECT 1;
$$ LANGUAGE SQL;
</programlisting>
@ -243,17 +303,26 @@ SELECT tf1(17, 100.0);
</programlisting>
</para>
<para>
In this example, we chose the name <literal>accountno</> for the first
argument, but this is the same as the name of a column in the
<literal>bank</> table. Within the <command>UPDATE</> command,
<literal>accountno</> refers to the column <literal>bank.accountno</>,
so <literal>tf1.accountno</> must be used to refer to the argument.
We could of course avoid this by using a different name for the argument.
</para>
<para>
In practice one would probably like a more useful result from the
function than a constant 1, so a more likely definition
is:
<programlisting>
CREATE FUNCTION tf1 (integer, numeric) RETURNS numeric AS $$
CREATE FUNCTION tf1 (accountno integer, debit numeric) RETURNS integer AS $$
UPDATE bank
SET balance = balance - $2
WHERE accountno = $1;
SELECT balance FROM bank WHERE accountno = $1;
SET balance = balance - debit
WHERE accountno = tf1.accountno;
SELECT balance FROM bank WHERE accountno = tf1.accountno;
$$ LANGUAGE SQL;
</programlisting>
@ -261,10 +330,10 @@ $$ LANGUAGE SQL;
The same thing could be done in one command using <literal>RETURNING</>:
<programlisting>
CREATE FUNCTION tf1 (integer, numeric) RETURNS numeric AS $$
CREATE FUNCTION tf1 (accountno integer, debit numeric) RETURNS integer AS $$
UPDATE bank
SET balance = balance - $2
WHERE accountno = $1
SET balance = balance - debit
WHERE accountno = tf1.accountno
RETURNING balance;
$$ LANGUAGE SQL;
</programlisting>
@ -275,11 +344,9 @@ $$ LANGUAGE SQL;
<title><acronym>SQL</acronym> Functions on Composite Types</title>
<para>
When writing functions with arguments of composite
types, we must not only specify which
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,
suppose that
When writing functions with arguments of composite types, we must not
only specify which argument we want but also the desired attribute
(field) of that argument. For example, suppose that
<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
is a function <function>double_salary</function> that computes what someone's
@ -524,39 +591,6 @@ SELECT getname(new_emp());
</para>
</sect2>
<sect2 id="xfunc-named-parameters">
<title><acronym>SQL</> Functions with Parameter Names</title>
<indexterm>
<primary>function</primary>
<secondary>named parameter</secondary>
</indexterm>
<para>
It is possible to attach names to a function's parameters, for example
<programlisting>
CREATE FUNCTION tf1 (acct_no integer, debit numeric) RETURNS numeric AS $$
UPDATE bank
SET balance = balance - $2
WHERE accountno = $1
RETURNING balance;
$$ LANGUAGE SQL;
</programlisting>
Here the first parameter has been given the name <literal>acct_no</>,
and the second parameter the name <literal>debit</>.
So far as the SQL function itself is concerned, these names are just
decoration; you must still refer to the parameters as <literal>$1</>,
<literal>$2</>, etc within the function body. (Some procedural
languages let you use the parameter names instead.) However,
attaching names to the parameters is useful for documentation purposes.
When a function has many parameters, it is also useful to use the names
while calling the function, as described in
<xref linkend="sql-syntax-calling-funcs">.
</para>
</sect2>
<sect2 id="xfunc-output-parameters">
<title><acronym>SQL</> Functions with Output Parameters</title>
@ -571,7 +605,7 @@ $$ LANGUAGE SQL;
<screen>
CREATE FUNCTION add_em (IN x int, IN y int, OUT sum int)
AS 'SELECT $1 + $2'
AS 'SELECT x + y'
LANGUAGE SQL;
SELECT add_em(3,7);
@ -588,7 +622,7 @@ SELECT add_em(3,7);
<screen>
CREATE FUNCTION sum_n_product (x int, y int, OUT sum int, OUT product int)
AS 'SELECT $1 + $2, $1 * $2'
AS 'SELECT x + y, x * y'
LANGUAGE SQL;
SELECT * FROM sum_n_product(11,42);