mirror of
https://github.com/postgres/postgres.git
synced 2025-06-03 00:02:26 -04:00
updates
This commit is contained in:
parent
d694260765
commit
1b506c9661
@ -1,10 +1,20 @@
|
|||||||
<!--
|
<!--
|
||||||
$Header: /cvsroot/pgsql/doc/src/sgml/xfunc.sgml,v 1.36 2001/09/13 15:55:23 petere Exp $
|
$Header: /cvsroot/pgsql/doc/src/sgml/xfunc.sgml,v 1.37 2001/09/15 19:56:59 petere Exp $
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<chapter id="xfunc">
|
<chapter id="xfunc">
|
||||||
<title id="xfunc-title">Extending <acronym>SQL</acronym>: Functions</title>
|
<title id="xfunc-title">Extending <acronym>SQL</acronym>: Functions</title>
|
||||||
|
|
||||||
|
<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>
|
<para>
|
||||||
As it turns out, part of defining a new type is the
|
As it turns out, part of defining a new type is the
|
||||||
definition of functions that describe its behavior.
|
definition of functions that describe its behavior.
|
||||||
@ -16,8 +26,8 @@ $Header: /cvsroot/pgsql/doc/src/sgml/xfunc.sgml,v 1.36 2001/09/13 15:55:23 peter
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
<productname>Postgres</productname> <acronym>SQL</acronym>
|
<productname>PostgreSQL</productname> provides four kinds of
|
||||||
provides three types of functions:
|
functions:
|
||||||
|
|
||||||
<itemizedlist>
|
<itemizedlist>
|
||||||
<listitem>
|
<listitem>
|
||||||
@ -29,7 +39,12 @@ $Header: /cvsroot/pgsql/doc/src/sgml/xfunc.sgml,v 1.36 2001/09/13 15:55:23 peter
|
|||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
procedural language
|
procedural language
|
||||||
functions (functions written in, for example, PL/Tcl or PL/pgSQL)
|
functions (functions written in, for example, <application>PL/Tcl</> or <application>PL/pgSQL</>)
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
internal functions
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
@ -38,7 +53,9 @@ $Header: /cvsroot/pgsql/doc/src/sgml/xfunc.sgml,v 1.36 2001/09/13 15:55:23 peter
|
|||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
Every kind
|
Every kind
|
||||||
of function can take a base type, a composite type or
|
of function can take a base type, a composite type or
|
||||||
some combination as arguments (parameters). In addition,
|
some combination as arguments (parameters). In addition,
|
||||||
@ -46,34 +63,37 @@ $Header: /cvsroot/pgsql/doc/src/sgml/xfunc.sgml,v 1.36 2001/09/13 15:55:23 peter
|
|||||||
a composite type. It's easiest to define <acronym>SQL</acronym>
|
a composite type. It's easiest to define <acronym>SQL</acronym>
|
||||||
functions, so we'll start with those. Examples in this section
|
functions, so we'll start with those. Examples in this section
|
||||||
can also be found in <filename>funcs.sql</filename>
|
can also be found in <filename>funcs.sql</filename>
|
||||||
and <filename>funcs.c</filename>.
|
and <filename>funcs.c</filename> in the tutorial directory.
|
||||||
</para>
|
</para>
|
||||||
|
</sect1>
|
||||||
|
|
||||||
<sect1 id="xfunc-sql">
|
<sect1 id="xfunc-sql">
|
||||||
<title>Query Language (<acronym>SQL</acronym>) Functions</title>
|
<title>Query Language (<acronym>SQL</acronym>) Functions</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
SQL functions execute an arbitrary list of SQL queries, returning
|
SQL functions execute an arbitrary list of SQL statements, returning
|
||||||
the results of the last query in the list. SQL functions in general
|
the results of the last query in the list. SQL functions in general
|
||||||
return sets. If their returntype is not specified as a
|
return sets. If their returntype is not specified as a
|
||||||
<literal>setof</literal>,
|
<literal>SETOF</literal>,
|
||||||
then an arbitrary element of the last query's result will be returned.
|
then an arbitrary element of the last query's result will be returned.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The body of a SQL function following AS
|
The body of an SQL function should be a list of one or more SQL
|
||||||
should be a list of queries separated by semicolons and
|
statements separated by semicolons. Note that because the syntax
|
||||||
bracketed within single-quote marks. Note that quote marks used in
|
of the <command>CREATE FUNCTION</command> requires the body of the
|
||||||
the queries must be escaped, by preceding them with a backslash.
|
function to be enclosed in single quotes, single quote marks used
|
||||||
|
in the body of the function must be escaped, by writing two single
|
||||||
|
quotes where one is desired.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Arguments to the SQL function may be referenced in the queries using
|
Arguments to the SQL function may be referenced in the function
|
||||||
a $n syntax: $1 refers to the first argument, $2 to the second, and so
|
body using the syntax <literal>$<replaceable>n</></>: $1 refers to
|
||||||
on. If an argument is complex, then a <firstterm>dot</firstterm>
|
the first argument, $2 to the second, and so on. If an argument
|
||||||
notation (e.g. <literal>$1.emp</literal>) may be
|
is of a composite type, then the <quote>dot notation</quote>,
|
||||||
used to access attributes of the argument or
|
e.g., <literal>$1.emp</literal>, may be used to access attributes
|
||||||
to invoke functions.
|
of the argument or to invoke functions.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<sect2>
|
<sect2>
|
||||||
@ -84,13 +104,12 @@ $Header: /cvsroot/pgsql/doc/src/sgml/xfunc.sgml,v 1.36 2001/09/13 15:55:23 peter
|
|||||||
which might be used to debit a bank account:
|
which might be used to debit a bank account:
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
CREATE FUNCTION tp1 (int4, float8)
|
CREATE FUNCTION tp1 (integer, double precision) RETURNS integer AS '
|
||||||
RETURNS int4
|
UPDATE bank
|
||||||
AS 'UPDATE bank
|
|
||||||
SET balance = bank.balance - $2
|
SET balance = bank.balance - $2
|
||||||
WHERE bank.acctountno = $1;
|
WHERE bank.acctountno = $1;
|
||||||
SELECT 1;'
|
SELECT 1;
|
||||||
LANGUAGE 'sql';
|
' LANGUAGE SQL;
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
|
||||||
A user could execute this function to debit account 17 by $100.00 as
|
A user could execute this function to debit account 17 by $100.00 as
|
||||||
@ -102,14 +121,15 @@ SELECT tp1( 17,100.0);
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The following more interesting example takes a single argument of type
|
The following more interesting example takes a single argument of
|
||||||
EMP, and retrieves multiple results:
|
type <type>EMP</type>, which is really a table that contains data
|
||||||
|
about employees, and retrieves multiple results:
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
CREATE FUNCTION hobbies (EMP) RETURNS SETOF hobbies
|
CREATE FUNCTION hobbies (EMP) RETURNS SETOF hobbies AS '
|
||||||
AS 'SELECT hobbies.* FROM hobbies
|
SELECT hobbies.* FROM hobbies
|
||||||
WHERE $1.name = hobbies.person'
|
WHERE $1.name = hobbies.person
|
||||||
LANGUAGE 'sql';
|
' LANGUAGE SQL;
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
@ -119,49 +139,49 @@ CREATE FUNCTION hobbies (EMP) RETURNS SETOF hobbies
|
|||||||
|
|
||||||
<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 <literal>int4</literal>:
|
simply returns a base type, such as <type>integer</type>:
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
CREATE FUNCTION one()
|
CREATE FUNCTION one() RETURNS integer AS '
|
||||||
RETURNS int4
|
SELECT 1 as RESULT;
|
||||||
AS 'SELECT 1 as RESULT;'
|
' LANGUAGE SQL;
|
||||||
LANGUAGE 'sql';
|
|
||||||
|
|
||||||
SELECT one() AS answer;
|
SELECT one() AS answer;
|
||||||
|
|
||||||
+-------+
|
|
||||||
|answer |
|
|
||||||
+-------+
|
|
||||||
|1 |
|
|
||||||
+-------+
|
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
|
||||||
|
<screen>
|
||||||
|
answer
|
||||||
|
--------
|
||||||
|
1
|
||||||
|
</screen>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Notice that we defined a column name for the function's result
|
Notice that we defined a column alias within the function body for the result of the function
|
||||||
(with the name RESULT), but this column name is not visible
|
(with the name <literal>RESULT</>), but this column alias is not visible
|
||||||
outside the function. Hence, the result is labelled answer
|
outside the function. Hence, the result is labelled <literal>answer</>
|
||||||
instead of one.
|
instead of <literal>one</>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
It's 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 $1
|
how we refer to the arguments within the function as <literal>$1</>
|
||||||
and $2:
|
and <literal>$2</>:
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
CREATE FUNCTION add_em(int4, int4)
|
CREATE FUNCTION add_em(integer, integer) RETURNS integer AS '
|
||||||
RETURNS int4
|
SELECT $1 + $2;
|
||||||
AS 'SELECT $1 + $2;'
|
' LANGUAGE SQL;
|
||||||
LANGUAGE 'sql';
|
|
||||||
|
|
||||||
SELECT add_em(1, 2) AS answer;
|
SELECT add_em(1, 2) AS answer;
|
||||||
|
|
||||||
+-------+
|
|
||||||
|answer |
|
|
||||||
+-------+
|
|
||||||
|3 |
|
|
||||||
+-------+
|
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
|
||||||
|
<screen>
|
||||||
|
answer
|
||||||
|
--------
|
||||||
|
3
|
||||||
|
</screen>
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
@ -170,37 +190,36 @@ SELECT add_em(1, 2) AS answer;
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
When specifying functions with arguments of composite
|
When specifying functions with arguments of composite
|
||||||
types (such as EMP), we must not only specify which
|
types (such as <type>EMP</type>), we must not only specify which
|
||||||
argument we want (as we did above with $1 and $2) but
|
argument we want (as we did above with <literal>$1</> and <literal>$2</literal>) but
|
||||||
also the attributes of that argument. For example,
|
also the attributes of that argument. For example,
|
||||||
take the function double_salary that computes what your
|
take the function <function>double_salary</function> that computes what your
|
||||||
salary would be if it were doubled:
|
salary would be if it were doubled:
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
CREATE FUNCTION double_salary(EMP)
|
CREATE FUNCTION double_salary(EMP) RETURNS integer AS '
|
||||||
RETURNS int4
|
SELECT $1.salary * 2 AS salary;
|
||||||
AS 'SELECT $1.salary * 2 AS salary;'
|
' LANGUAGE SQL;
|
||||||
LANGUAGE 'sql';
|
|
||||||
|
|
||||||
SELECT name, double_salary(EMP) AS dream
|
SELECT name, double_salary(EMP) AS dream
|
||||||
FROM EMP
|
FROM EMP
|
||||||
WHERE EMP.cubicle ~= point '(2,1)';
|
WHERE EMP.cubicle ~= point '(2,1)';
|
||||||
|
|
||||||
|
|
||||||
+-----+-------+
|
|
||||||
|name | dream |
|
|
||||||
+-----+-------+
|
|
||||||
|Sam | 2400 |
|
|
||||||
+-----+-------+
|
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
|
||||||
|
<screen>
|
||||||
|
name | dream
|
||||||
|
------+-------
|
||||||
|
Sam | 2400
|
||||||
|
</screen>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Notice the use of the syntax $1.salary.
|
Notice the use of the syntax <literal>$1.salary</literal>.
|
||||||
Before launching into the subject of functions that
|
Before launching into the subject of functions that
|
||||||
return composite types, we must first introduce the
|
return composite types, we must first introduce the
|
||||||
function notation for projecting attributes. The simple way
|
function notation for projecting attributes. The simple way
|
||||||
to explain this is that we can usually use the
|
to explain this is that we can usually use the
|
||||||
notations attribute(table) and table.attribute interchangably:
|
notations <literal>attribute(table)</> and <literal>table.attribute</> interchangably:
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
--
|
--
|
||||||
@ -210,32 +229,33 @@ SELECT name, double_salary(EMP) AS dream
|
|||||||
SELECT name(EMP) AS youngster
|
SELECT name(EMP) AS youngster
|
||||||
FROM EMP
|
FROM EMP
|
||||||
WHERE age(EMP) < 30;
|
WHERE age(EMP) < 30;
|
||||||
|
|
||||||
+----------+
|
|
||||||
|youngster |
|
|
||||||
+----------+
|
|
||||||
|Sam |
|
|
||||||
+----------+
|
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
|
||||||
|
<screen>
|
||||||
|
youngster
|
||||||
|
-----------
|
||||||
|
Sam
|
||||||
|
</screen>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
As we shall see, however, this is not always the case.
|
As we shall see, however, this is not always the case.
|
||||||
This function notation is important when we want to use
|
This function notation is important when we want to use
|
||||||
a function that returns a single row. We do this
|
a function that returns a single row. We do this
|
||||||
by assembling the entire row within the function,
|
by assembling the entire row within the function,
|
||||||
attribute by attribute. This is an example of a function
|
attribute by attribute. This is an example of a function
|
||||||
that returns a single EMP row:
|
that returns a single <type>EMP</type> row:
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
CREATE FUNCTION new_emp()
|
CREATE FUNCTION new_emp() RETURNS EMP AS '
|
||||||
RETURNS EMP
|
SELECT text ''None'' AS name,
|
||||||
AS 'SELECT text ''None'' AS name,
|
|
||||||
1000 AS salary,
|
1000 AS salary,
|
||||||
25 AS age,
|
25 AS age,
|
||||||
point ''(2,2)'' AS cubicle'
|
point ''(2,2)'' AS cubicle;
|
||||||
LANGUAGE 'sql';
|
' LANGUAGE SQL;
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
In this case we have specified each of the attributes
|
In this case we have specified each of the attributes
|
||||||
with a constant value, but any computation or expression
|
with a constant value, but any computation or expression
|
||||||
@ -247,19 +267,19 @@ CREATE FUNCTION new_emp()
|
|||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
The target list order must be exactly the same as
|
The target list order must be exactly the same as
|
||||||
that in which the attributes appear in the CREATE
|
that in which the attributes appear in the <command>CREATE
|
||||||
TABLE statement that defined the composite type.
|
TABLE</command> statement that defined the table underlying the composite type.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
You must typecast the expressions to match the
|
You must typecast the expressions to match the
|
||||||
composite type's definition, or you will get errors like this:
|
definition of the composite type, or you will get errors like this:
|
||||||
<programlisting>
|
<screen>
|
||||||
<computeroutput>
|
<computeroutput>
|
||||||
ERROR: function declared to return emp returns varchar instead of text at column 1
|
ERROR: function declared to return emp returns varchar instead of text at column 1
|
||||||
</computeroutput>
|
</computeroutput>
|
||||||
</programlisting>
|
</screen>
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
@ -271,13 +291,13 @@ ERROR: function declared to return emp returns varchar instead of text at colum
|
|||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
SELECT name(new_emp()) AS nobody;
|
SELECT name(new_emp()) AS nobody;
|
||||||
|
|
||||||
+-------+
|
|
||||||
|nobody |
|
|
||||||
+-------+
|
|
||||||
|None |
|
|
||||||
+-------+
|
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
|
||||||
|
<screen>
|
||||||
|
nobody
|
||||||
|
--------
|
||||||
|
None
|
||||||
|
</screen>
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
@ -288,18 +308,18 @@ SELECT name(new_emp()) AS nobody;
|
|||||||
the other (dot) syntax for projection when combined
|
the other (dot) syntax for projection when combined
|
||||||
with function calls.
|
with function calls.
|
||||||
|
|
||||||
<programlisting>
|
<screen>
|
||||||
SELECT new_emp().name AS nobody;
|
SELECT new_emp().name AS nobody;
|
||||||
NOTICE:parser: syntax error at or near "."
|
NOTICE:parser: syntax error at or near "."
|
||||||
</programlisting>
|
</screen>
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
Any collection of commands in the <acronym>SQL</acronym> query
|
Any collection of commands in the <acronym>SQL</acronym>
|
||||||
language can be packaged together and defined as a function.
|
language can be packaged together and defined as a function.
|
||||||
The commands can include updates (i.e.,
|
The commands can include data modification (i.e.,
|
||||||
<command>INSERT</command>, <command>UPDATE</command>, and
|
<command>INSERT</command>, <command>UPDATE</command>, and
|
||||||
<command>DELETE</command>) as well
|
<command>DELETE</command>) as well
|
||||||
as <command>SELECT</command> queries. However, the final command
|
as <command>SELECT</command> queries. However, the final command
|
||||||
@ -307,21 +327,20 @@ NOTICE:parser: syntax error at or near "."
|
|||||||
specified as the function's return type.
|
specified as the function's return type.
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
CREATE FUNCTION clean_EMP ()
|
CREATE FUNCTION clean_EMP () RETURNS integer AS '
|
||||||
RETURNS int4
|
DELETE FROM EMP
|
||||||
AS 'DELETE FROM EMP
|
|
||||||
WHERE EMP.salary <= 0;
|
WHERE EMP.salary <= 0;
|
||||||
SELECT 1 AS ignore_this;'
|
SELECT 1 AS ignore_this;
|
||||||
LANGUAGE 'sql';
|
' LANGUAGE SQL;
|
||||||
|
|
||||||
SELECT clean_EMP();
|
SELECT clean_EMP();
|
||||||
|
|
||||||
+--+
|
|
||||||
|x |
|
|
||||||
+--+
|
|
||||||
|1 |
|
|
||||||
+--+
|
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
|
||||||
|
<screen>
|
||||||
|
x
|
||||||
|
---
|
||||||
|
1
|
||||||
|
</screen>
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
</sect1>
|
</sect1>
|
||||||
@ -330,18 +349,19 @@ SELECT clean_EMP();
|
|||||||
<title>Procedural Language Functions</title>
|
<title>Procedural Language Functions</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Procedural languages aren't built into Postgres. They are offered
|
Procedural languages aren't built into the <productname>PostgreSQL</productname> server; they are offered
|
||||||
by loadable modules. Please refer to the documentation for the
|
by loadable modules. Please refer to the documentation of the
|
||||||
PL in question for details about the syntax and how the AS
|
procedural language in question for details about the syntax and how the function body
|
||||||
clause is interpreted by the PL handler.
|
is interpreted for each language.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
There are currently four procedural languages available in the
|
There are currently four procedural languages available in the
|
||||||
standard <productname>PostgreSQL</productname> distribution:
|
standard <productname>PostgreSQL</productname> distribution:
|
||||||
PL/pgSQL, PL/Tcl, PL/Perl, and PL/Python. Other languages can be
|
<application>PL/pgSQL</application>, <application>PL/Tcl</application>,
|
||||||
|
<application>PL/Perl</application>, and <application>PL/Python</application>. Other languages can be
|
||||||
defined by users. Refer to <xref linkend="xplang"> for more
|
defined by users. Refer to <xref linkend="xplang"> for more
|
||||||
information.
|
information. The basics of developing a new procedural language are covered in <xref linkend="xfunc-plhandler">.
|
||||||
</para>
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
@ -350,22 +370,39 @@ SELECT clean_EMP();
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
Internal functions are functions written in C that have been statically
|
Internal functions are functions written in C that have been statically
|
||||||
linked into the <productname>Postgres</productname> backend
|
linked into the <productname>PostgreSQL</productname> server.
|
||||||
process. The AS
|
The <quote>body</quote> of the function definition
|
||||||
clause gives the C-language name of the function, which need not be the
|
specifies the C-language name of the function, which need not be the
|
||||||
same as the name being declared for SQL use.
|
same as the name being declared for SQL use.
|
||||||
(For reasons of backwards compatibility, an empty AS
|
(For reasons of backwards compatibility, an empty body
|
||||||
string is accepted as meaning that the C-language function name is the
|
is accepted as meaning that the C-language function name is the
|
||||||
same as the SQL name.) Normally, all internal functions present in the
|
same as the SQL name.)
|
||||||
backend are declared as SQL functions during database initialization,
|
|
||||||
but a user could use <command>CREATE FUNCTION</command>
|
|
||||||
to create additional alias names for an internal function.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
|
Normally, all internal functions present in the
|
||||||
|
backend are declared during the initialization of the database cluster (<command>initdb</command>),
|
||||||
|
but a user could use <command>CREATE FUNCTION</command>
|
||||||
|
to create additional alias names for an internal function.
|
||||||
Internal functions are declared in <command>CREATE FUNCTION</command>
|
Internal functions are declared in <command>CREATE FUNCTION</command>
|
||||||
with language name <literal>internal</literal>.
|
with language name <literal>internal</literal>. For instance, to
|
||||||
|
create an alias for the <function>sqrt</function> function:
|
||||||
|
<programlisting>
|
||||||
|
CREATE FUNCTION square_root(double precision) RETURNS double precision
|
||||||
|
AS 'dsqrt'
|
||||||
|
LANGUAGE INTERNAL
|
||||||
|
WITH (isStrict);
|
||||||
|
</programlisting>
|
||||||
|
(Most internal functions expect to be declared <quote>strict</quote>.)
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<note>
|
||||||
|
<para>
|
||||||
|
Not all <quote>predefined</quote> functions are
|
||||||
|
<quote>internal</quote> in the above sense. Some predefined
|
||||||
|
functions are written in SQL.
|
||||||
|
</para>
|
||||||
|
</note>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
<sect1 id="xfunc-c">
|
<sect1 id="xfunc-c">
|
||||||
@ -495,23 +532,26 @@ SELECT clean_EMP();
|
|||||||
<title>Base Types in C-Language Functions</title>
|
<title>Base Types in C-Language Functions</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The following table gives the C type required for parameters in the C
|
<xref linkend="xfunc-c-type-table"> gives the C type required for
|
||||||
functions that will be loaded into Postgres. The <quote>Defined In</quote>
|
parameters in the C functions that will be loaded into Postgres.
|
||||||
column gives the actual header file (in the
|
The <quote>Defined In</quote> column gives the header file that
|
||||||
<filename>.../src/backend/</filename>
|
needs to be included to get the type definition. (The actual
|
||||||
directory) that the equivalent C type is defined. Note that you should
|
definition may be in a different file that is included by the
|
||||||
always include <filename>postgres.h</filename> first, and that in turn
|
listed file. It is recommended that users stick to the defined
|
||||||
includes <filename>c.h</filename>.
|
interface.) Note that you should always include
|
||||||
|
<filename>postgres.h</filename> first in any source file, because
|
||||||
|
it declares a number of things that you will need anyway.
|
||||||
|
</para>
|
||||||
|
|
||||||
<table tocentry="1">
|
<table tocentry="1" id="xfunc-c-type-table">
|
||||||
<title>Equivalent C Types
|
<title>Equivalent C Types
|
||||||
for Built-In <productname>Postgres</productname> Types</title>
|
for Built-In <productname>PostgreSQL</productname> Types</title>
|
||||||
<titleabbrev>Equivalent C Types</titleabbrev>
|
<titleabbrev>Equivalent C Types</titleabbrev>
|
||||||
<tgroup cols="3">
|
<tgroup cols="3">
|
||||||
<thead>
|
<thead>
|
||||||
<row>
|
<row>
|
||||||
<entry>
|
<entry>
|
||||||
Built-In Type
|
SQL Type
|
||||||
</entry>
|
</entry>
|
||||||
<entry>
|
<entry>
|
||||||
C Type
|
C Type
|
||||||
@ -523,134 +563,158 @@ SELECT clean_EMP();
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<row>
|
<row>
|
||||||
<entry>abstime</entry>
|
<entry><type>abstime</type></entry>
|
||||||
<entry>AbsoluteTime</entry>
|
<entry><type>AbsoluteTime</type></entry>
|
||||||
<entry>utils/nabstime.h</entry>
|
<entry><filename>utils/nabstime.h</filename></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry>bool</entry>
|
<entry><type>boolean</type></entry>
|
||||||
<entry>bool</entry>
|
<entry><type>bool</type></entry>
|
||||||
<entry>include/c.h</entry>
|
<entry><filename>postgres.h</filename> (maybe compiler built-in)</entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry>box</entry>
|
<entry><type>box</type></entry>
|
||||||
<entry>(BOX *)</entry>
|
<entry><type>BOX*</type></entry>
|
||||||
<entry>utils/geo-decls.h</entry>
|
<entry><filename>utils/geo-decls.h</filename></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry>bytea</entry>
|
<entry><type>bytea</type></entry>
|
||||||
<entry>(bytea *)</entry>
|
<entry><type>bytea*</type></entry>
|
||||||
<entry>include/postgres.h</entry>
|
<entry><filename>postgres.h</filename></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry>"char"</entry>
|
<entry><type>"char"</type></entry>
|
||||||
<entry>char</entry>
|
<entry><type>char</type></entry>
|
||||||
<entry>N/A</entry>
|
<entry>(compiler built-in)</entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry>cid</entry>
|
<entry><type>character</type></entry>
|
||||||
<entry>CID</entry>
|
<entry><type>BpChar*</type></entry>
|
||||||
<entry>include/postgres.h</entry>
|
<entry><filename>postgres.h</filename></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry>datetime</entry>
|
<entry><type>cid</type></entry>
|
||||||
<entry>(DateTime *)</entry>
|
<entry><type>CommandId</type></entry>
|
||||||
<entry>include/c.h or include/postgres.h</entry>
|
<entry><filename>postgres.h</filename></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry>int2</entry>
|
<entry><type>date</type></entry>
|
||||||
<entry>int2 or int16</entry>
|
<entry><type>DateADT</type></entry>
|
||||||
<entry>include/postgres.h</entry>
|
<entry><filename>utils/date.h</filename></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry>int2vector</entry>
|
<entry><type>smallint</type> (<type>int2</type>)</entry>
|
||||||
<entry>(int2vector *)</entry>
|
<entry><type>int2</type> or <type>int16</type></entry>
|
||||||
<entry>include/postgres.h</entry>
|
<entry><filename>postgres.h</filename></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry>int4</entry>
|
<entry><type>int2vector</type></entry>
|
||||||
<entry>int4 or int32</entry>
|
<entry><type>int2vector*</type></entry>
|
||||||
<entry>include/postgres.h</entry>
|
<entry><filename>postgres.h</filename></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry>float4</entry>
|
<entry><type>integer</type> (<type>int4</type>)</entry>
|
||||||
<entry>(float4 *)</entry>
|
<entry><type>int4</type> or <type>int32</type></entry>
|
||||||
<entry>include/c.h or include/postgres.h</entry>
|
<entry><filename>postgres.h</filename></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry>float8</entry>
|
<entry><type>real</type> (<type>float4</type>)</entry>
|
||||||
<entry>(float8 *)</entry>
|
<entry><type>float4*</type></entry>
|
||||||
<entry>include/c.h or include/postgres.h</entry>
|
<entry><filename>postgres.h</filename></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry>lseg</entry>
|
<entry><type>double precision</type> (<type>float8</type>)</entry>
|
||||||
<entry>(LSEG *)</entry>
|
<entry><type>float8*</type></entry>
|
||||||
<entry>include/geo-decls.h</entry>
|
<entry><filename>postgres.h</filename></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry>name</entry>
|
<entry><type>interval</type></entry>
|
||||||
<entry>(Name)</entry>
|
<entry><type>Interval*</type></entry>
|
||||||
<entry>include/postgres.h</entry>
|
<entry><filename>utils/timestamp.h</filename></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry>oid</entry>
|
<entry><type>lseg</type></entry>
|
||||||
<entry>oid</entry>
|
<entry><type>LSEG*</type></entry>
|
||||||
<entry>include/postgres.h</entry>
|
<entry><filename>utils/geo-decls.h</filename></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry>oidvector</entry>
|
<entry><type>name</type></entry>
|
||||||
<entry>(oidvector *)</entry>
|
<entry><type>Name</type></entry>
|
||||||
<entry>include/postgres.h</entry>
|
<entry><filename>postgres.h</filename></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry>path</entry>
|
<entry><type>oid</type></entry>
|
||||||
<entry>(PATH *)</entry>
|
<entry><type>Oid</type></entry>
|
||||||
<entry>utils/geo-decls.h</entry>
|
<entry><filename>postgres.h</filename></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry>point</entry>
|
<entry><type>oidvector</type></entry>
|
||||||
<entry>(POINT *)</entry>
|
<entry><type>oidvector*</type></entry>
|
||||||
<entry>utils/geo-decls.h</entry>
|
<entry><filename>postgres.h</filename></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry>regproc</entry>
|
<entry><type>path</type></entry>
|
||||||
<entry>regproc or REGPROC</entry>
|
<entry><type>PATH*</type></entry>
|
||||||
<entry>include/postgres.h</entry>
|
<entry><filename>utils/geo-decls.h</filename></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry>reltime</entry>
|
<entry><type>point</type></entry>
|
||||||
<entry>RelativeTime</entry>
|
<entry><type>POINT*</type></entry>
|
||||||
<entry>utils/nabstime.h</entry>
|
<entry><filename>utils/geo-decls.h</filename></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry>text</entry>
|
<entry><type>regproc</type></entry>
|
||||||
<entry>(text *)</entry>
|
<entry><type>regproc</type></entry>
|
||||||
<entry>include/postgres.h</entry>
|
<entry><filename>postgres.h</filename></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry>tid</entry>
|
<entry><type>reltime</type></entry>
|
||||||
<entry>ItemPointer</entry>
|
<entry><type>RelativeTime</type></entry>
|
||||||
<entry>storage/itemptr.h</entry>
|
<entry><filename>utils/nabstime.h</filename></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry>timespan</entry>
|
<entry><type>text</type></entry>
|
||||||
<entry>(TimeSpan *)</entry>
|
<entry><type>text*</type></entry>
|
||||||
<entry>include/c.h or include/postgres.h</entry>
|
<entry><filename>postgres.h</filename></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry>tinterval</entry>
|
<entry><type>tid</type></entry>
|
||||||
<entry>TimeInterval</entry>
|
<entry><type>ItemPointer</type></entry>
|
||||||
<entry>utils/nabstime.h</entry>
|
<entry><filename>storage/itemptr.h</filename></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry>xid</entry>
|
<entry><type>time</type></entry>
|
||||||
<entry>(XID *)</entry>
|
<entry><type>TimeADT</type></entry>
|
||||||
<entry>include/postgres.h</entry>
|
<entry><filename>utils/date.h</filename></entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry><type>time with time zone</type></entry>
|
||||||
|
<entry><type>TimeTzADT</type></entry>
|
||||||
|
<entry><filename>utils/date.h</filename></entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry><type>timestamp</type></entry>
|
||||||
|
<entry><type>Timestamp*</type></entry>
|
||||||
|
<entry><filename>utils/timestamp.h</filename></entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry><type>tinterval</type></entry>
|
||||||
|
<entry><type>TimeInterval</type></entry>
|
||||||
|
<entry><filename>utils/nabstime.h</filename></entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry><type>varchar</type></entry>
|
||||||
|
<entry><type>VarChar*</type></entry>
|
||||||
|
<entry><filename>postgres.h</filename></entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry><type>xid</type></entry>
|
||||||
|
<entry><type>TransactionId</type></entry>
|
||||||
|
<entry><filename>postgres.h</filename></entry>
|
||||||
</row>
|
</row>
|
||||||
</tbody>
|
</tbody>
|
||||||
</tgroup>
|
</tgroup>
|
||||||
</table>
|
</table>
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Internally, <productname>Postgres</productname> regards a
|
Internally, <productname>Postgres</productname> regards a
|
||||||
@ -683,28 +747,31 @@ SELECT clean_EMP();
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
By-value types can only be 1, 2 or 4 bytes in length
|
By-value types can only be 1, 2 or 4 bytes in length
|
||||||
(also 8 bytes, if sizeof(Datum) is 8 on your machine).
|
(also 8 bytes, if <literal>sizeof(Datum)</literal> is 8 on your machine).
|
||||||
You should be careful
|
You should be careful
|
||||||
to define your types such that they will be the same
|
to define your types such that they will be the same
|
||||||
size (in bytes) on all architectures. For example, the
|
size (in bytes) on all architectures. For example, the
|
||||||
<literal>long</literal> type is dangerous because it
|
<literal>long</literal> type is dangerous because it
|
||||||
is 4 bytes on some machines and 8 bytes on others, whereas
|
is 4 bytes on some machines and 8 bytes on others, whereas
|
||||||
<literal>int</literal> type is 4 bytes on most
|
<type>int</type> type is 4 bytes on most
|
||||||
Unix machines (though not on most
|
Unix machines. A reasonable implementation of
|
||||||
personal computers). A reasonable implementation of
|
the <type>int4</type> type on Unix
|
||||||
the <literal>int4</literal> type on Unix
|
|
||||||
machines might be:
|
machines might be:
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
/* 4-byte integer, passed by value */
|
/* 4-byte integer, passed by value */
|
||||||
typedef int int4;
|
typedef int int4;
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
|
||||||
|
<productname>PostgreSQL</productname> automatically figures
|
||||||
|
things out so that the integer types really have the size they
|
||||||
|
advertise.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
On the other hand, fixed-length types of any size may
|
On the other hand, fixed-length types of any size may
|
||||||
be passed by-reference. For example, here is a sample
|
be passed by-reference. For example, here is a sample
|
||||||
implementation of a <productname>Postgres</productname> type:
|
implementation of a <productname>PostgreSQL</productname> type:
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
/* 16-byte structure, passed by reference */
|
/* 16-byte structure, passed by reference */
|
||||||
@ -1252,7 +1319,6 @@ LANGUAGE 'c';
|
|||||||
to include <filename>postgres.h</filename> <emphasis>first</>,
|
to include <filename>postgres.h</filename> <emphasis>first</>,
|
||||||
before any other system or user header files.
|
before any other system or user header files.
|
||||||
Including <filename>postgres.h</filename> will also include
|
Including <filename>postgres.h</filename> will also include
|
||||||
<filename>c.h</filename>,
|
|
||||||
<filename>elog.h</filename> and <filename>palloc.h</filename>
|
<filename>elog.h</filename> and <filename>palloc.h</filename>
|
||||||
for you.
|
for you.
|
||||||
</para>
|
</para>
|
||||||
@ -1291,71 +1357,66 @@ LANGUAGE 'c';
|
|||||||
<title>Function Overloading</title>
|
<title>Function Overloading</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
More than one function may be defined with the same name, so long as
|
More than one function may be defined with the same name, so long
|
||||||
the arguments they take are different. In other words, function names
|
as the arguments they take are different. In other words,
|
||||||
can be <firstterm>overloaded</firstterm>.
|
function names can be <firstterm>overloaded</firstterm>. When a
|
||||||
|
query is executed, the server will determine which function to
|
||||||
|
call from the data types and the number of the provided arguments.
|
||||||
|
Overloading can also be used to simulate functions with a variable
|
||||||
|
number of arguments, up to a finite maximum number.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
A function may also have the same name as an attribute. In the case
|
A function may also have the same name as an attribute. In the case
|
||||||
that there is an ambiguity between a function on a complex type and
|
that there is an ambiguity between a function on a complex type and
|
||||||
an attribute of the complex type, the attribute will always be used.
|
an attribute of the complex type, the attribute will always be used.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<sect2>
|
|
||||||
<title>Name Space Conflicts</title>
|
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
As of <productname>Postgres</productname> 7.0, the alternative
|
When creating a family of overloaded functions, one should be
|
||||||
form of the AS clause for the SQL
|
careful not to create ambiguities. For instance, given the
|
||||||
<command>CREATE FUNCTION</command> command
|
functions
|
||||||
decouples the SQL function name from the function name in the C
|
<programlisting>
|
||||||
source code. This is now the preferred technique to accomplish
|
CREATE FUNCTION test(int, real) RETURNS ...
|
||||||
function overloading.
|
CREATE FUNCTION test(smallint, double precision) RETURNS ...
|
||||||
</para>
|
</programlisting>
|
||||||
|
it is not immediately clear which function would be called with
|
||||||
<sect3>
|
some trivial input like <literal>test(1, 1.5)</literal>. The
|
||||||
<title>Pre-7.0</title>
|
currently implemented resolution rules are described in the
|
||||||
|
<citetitle>User's Guide</citetitle>, but it is unwise to design a
|
||||||
<para>
|
system that subtly relies on this behavior.
|
||||||
For functions written in C, the SQL name declared in
|
|
||||||
<command>CREATE FUNCTION</command>
|
|
||||||
must be exactly the same as the actual name of the function in the
|
|
||||||
C code (hence it must be a legal C function name).
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
There is a subtle implication of this restriction: while the
|
When overloading C language functions, there is an additional
|
||||||
dynamic loading routines in most operating systems are more than
|
constraint: The C name of each function in the family of
|
||||||
happy to allow you to load any number of shared libraries that
|
overloaded functions must be different from the C names of all
|
||||||
contain conflicting (identically-named) function names, they may
|
other functions, either internal or dynamically loaded. If this
|
||||||
in fact botch the load in interesting ways. For example, if you
|
rule is violated, the behavior is not portable. You might get a
|
||||||
define a dynamically-loaded function that happens to have the
|
run-time linker error, or one of the functions will get called
|
||||||
same name as a function built into Postgres, the DEC OSF/1 dynamic
|
(usually the internal one). The alternative form of the
|
||||||
loader causes Postgres to call the function within itself rather than
|
<literal>AS</> clause for the SQL <command>CREATE
|
||||||
allowing Postgres to call your function. Hence, if you want your
|
FUNCTION</command> command decouples the SQL function name from
|
||||||
function to be used on different architectures, we recommend that
|
the function name in the C source code. E.g.,
|
||||||
you do not overload C function names.
|
<programlisting>
|
||||||
|
CREATE FUNCTION test(int) RETURNS int
|
||||||
|
AS '<replaceable>filename</>', 'test_1arg'
|
||||||
|
LANGUAGE C;
|
||||||
|
CREATE FUNCTION test(int, int) RETURNS int
|
||||||
|
AS '<replaceable>filename</>', 'test_2arg'
|
||||||
|
LANGUAGE C;
|
||||||
|
</programlisting>
|
||||||
|
The names of the C functions here reflect one of many possible conventions.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
There is a clever trick to get around the problem just described.
|
Prior to <productname>PostgreSQL</productname> 7.0, this
|
||||||
Since there is no problem overloading SQL functions, you can
|
alternative syntax did not exist. There is a trick to get around
|
||||||
define a set of C functions with different names and then define
|
the problem, by defining a set of C functions with different names
|
||||||
a set of identically-named SQL function wrappers that take the
|
and then define a set of identically-named SQL function wrappers
|
||||||
appropriate argument types and call the matching C function.
|
that take the appropriate argument types and call the matching C
|
||||||
|
function.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
|
||||||
Another solution is not to use dynamic loading, but to link your
|
|
||||||
functions into the backend statically and declare them as INTERNAL
|
|
||||||
functions. Then, the functions must all have distinct C names but
|
|
||||||
they can be declared with the same SQL names (as long as their
|
|
||||||
argument types differ, of course). This way avoids the overhead of
|
|
||||||
an SQL wrapper function, at the cost of more effort to prepare a
|
|
||||||
custom backend executable. (This option is only available in version
|
|
||||||
6.5 and later, since prior versions required internal functions to
|
|
||||||
have the same name in SQL as in the C code.)
|
|
||||||
</para>
|
|
||||||
</sect3>
|
|
||||||
</sect2>
|
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user