mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-01-12 18:34:36 +08:00
August version of docs superceded by sgml version from Jan.
This commit is contained in:
parent
a00c668139
commit
3d22596fe7
@ -1,448 +0,0 @@
|
|||||||
PL/pgSQL
|
|
||||||
A procedural language for the PostgreSQL RDBMS
|
|
||||||
|
|
||||||
Jan Wieck <jwieck@debis.com>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Preface
|
|
||||||
|
|
||||||
PL/pgSQL is a procedural language based on SQL designed for
|
|
||||||
the PostgreSQL database system.
|
|
||||||
|
|
||||||
The extensibility features of PostgreSQL are mostly based on
|
|
||||||
the ability to define functions for various operations.
|
|
||||||
Functions could have been written in PostgreSQL's SQL dialect
|
|
||||||
or in the C programming language. Functions written in C are
|
|
||||||
compiled into a shared object and loaded by the database
|
|
||||||
backend process on demand. Also the trigger features of
|
|
||||||
PostgreSQL are based on functions but required the use of the
|
|
||||||
C language.
|
|
||||||
|
|
||||||
Since version 6.3 PostgreSQL supports the definition of
|
|
||||||
procedural languages. In the case of a function or trigger
|
|
||||||
procedure defined in a procedural language, the database has
|
|
||||||
no builtin knowlege how to interpret the functions source
|
|
||||||
text. Instead, the function and trigger calls are passed into
|
|
||||||
a handler that knows the details of the language. The
|
|
||||||
handler itself is a function compiled into a shared object
|
|
||||||
and loaded on demand.
|
|
||||||
|
|
||||||
|
|
||||||
Overview
|
|
||||||
|
|
||||||
The PL/pgSQL language is case insensitive. All keywords and
|
|
||||||
identifiers can be used in upper-/lowercase mixed.
|
|
||||||
|
|
||||||
PL/pgSQL is a block oriented language. A block is defined as
|
|
||||||
|
|
||||||
[<<label>>]
|
|
||||||
[DECLARE
|
|
||||||
-- declarations]
|
|
||||||
BEGIN
|
|
||||||
-- statements
|
|
||||||
END;
|
|
||||||
|
|
||||||
There can be any number of subblocks in the statements
|
|
||||||
section of a block. Subblocks can be used to hide variables
|
|
||||||
from outside a block of statements (see Scope and visability
|
|
||||||
below). The variables declared in the declarations section
|
|
||||||
preceding a block are initialized to their default values
|
|
||||||
every time the block is entered, not only once per function
|
|
||||||
call.
|
|
||||||
|
|
||||||
It is important not to misunderstand the meaning of BEGIN/END
|
|
||||||
for grouping statements in PL/pgSQL and the database commands
|
|
||||||
for transaction control. Functions or trigger procedures
|
|
||||||
cannot start or commit transactions and PostgreSQL
|
|
||||||
transactions cannot have subtransactions.
|
|
||||||
|
|
||||||
|
|
||||||
Comments
|
|
||||||
|
|
||||||
There are two types of comments in PL/pgSQL. A double dash
|
|
||||||
'--' starts a comment that extends to the end of the line. A
|
|
||||||
'/*' starts a block comment that extends to the next '*/'.
|
|
||||||
Block comments cannot be nested, but double dash comments can
|
|
||||||
be enclosed into a block comment and double dashes can hide
|
|
||||||
'/*' and '*/'.
|
|
||||||
|
|
||||||
|
|
||||||
Declarations
|
|
||||||
|
|
||||||
All variables, rows and records used in a block or it's
|
|
||||||
subblocks must be declared in the declarations section of the
|
|
||||||
block except for the loop variable of a FOR loop iterating
|
|
||||||
over a range of integer values. The parameters given to the
|
|
||||||
function are automatically declared with the usual
|
|
||||||
identifiers $n. The declarations have the following syntax:
|
|
||||||
|
|
||||||
<name> [CONSTANT] <type> [NOT NULL]
|
|
||||||
[DEFAULT | := <value>];
|
|
||||||
|
|
||||||
Declares a variable of the specified type. If the
|
|
||||||
variable is declared as CONSTANT, the value cannot be
|
|
||||||
changed. If NOT NULL is specified, an assignment of a
|
|
||||||
NULL value results in a runtime error. Since the
|
|
||||||
default value of a variable is the SQL NULL value,
|
|
||||||
all variables declared as NOT NULL must also have a
|
|
||||||
default value.
|
|
||||||
|
|
||||||
The default value is evaluated at the actual function
|
|
||||||
call. So assigning 'now' to an abstime variable
|
|
||||||
causes the variable to have the time of the actual
|
|
||||||
function call, not when the function was compiled
|
|
||||||
(during it's first call since the lifetime of the
|
|
||||||
database connection).
|
|
||||||
|
|
||||||
<name> <class>%ROWTYPE;
|
|
||||||
|
|
||||||
Declares a row with the structure of the given class.
|
|
||||||
Class must be an existing table- or viewname of the
|
|
||||||
database. The fields of the row are accessed in the
|
|
||||||
dot notation. Parameters to a procedure could be
|
|
||||||
tuple types. In that case the corresponding
|
|
||||||
identifier $n will be a rowtype. Only the user
|
|
||||||
attributes of a tuple are accessible in the row.
|
|
||||||
There must be no whitespaces between the classname,
|
|
||||||
the percent and the ROWTYPE keyword.
|
|
||||||
|
|
||||||
The fields of the rowtype inherit the tables
|
|
||||||
fieldsizes for char() etc. data types (atttypmod
|
|
||||||
from pg_attribute).
|
|
||||||
|
|
||||||
<name> RECORD;
|
|
||||||
|
|
||||||
Records are similar to rowtypes, but they have no
|
|
||||||
predefined structure They are used in selections and
|
|
||||||
FOR loops to hold one actual database tuple from a
|
|
||||||
select operation. One and the same record can be used
|
|
||||||
in different selections. Accessing a record or an
|
|
||||||
attempt to assign a value to a record field when
|
|
||||||
there's no actual tuple in it results in a runtime
|
|
||||||
error.
|
|
||||||
|
|
||||||
The new and old tuples in triggers are given to the
|
|
||||||
trigger procedure as records. This is necessary,
|
|
||||||
because under PostgreSQL one and the same trigger
|
|
||||||
procedure can handle trigger events for different
|
|
||||||
tables.
|
|
||||||
|
|
||||||
<name> ALIAS FOR $n;
|
|
||||||
|
|
||||||
For better readability of the code it's possible to
|
|
||||||
define an alias for a positional parameter to the
|
|
||||||
function.
|
|
||||||
|
|
||||||
RENAME <oldname> TO <newname>;
|
|
||||||
|
|
||||||
Change the name of a variable, record or rowtype.
|
|
||||||
This is useful if new or old should be referenced by
|
|
||||||
another name inside a trigger procedure.
|
|
||||||
|
|
||||||
Datatypes
|
|
||||||
|
|
||||||
The type of a variable can be any of the existing data types
|
|
||||||
of the database. <type> above is defined as:
|
|
||||||
|
|
||||||
postgesql-basetype
|
|
||||||
or variable%TYPE
|
|
||||||
or rowtype.field%TYPE
|
|
||||||
or class.field%TYPE
|
|
||||||
|
|
||||||
As for the rowtype declaration, there must be no whitespaces
|
|
||||||
between the classname, the percent and the TYPE keyword.
|
|
||||||
|
|
||||||
Expressions
|
|
||||||
|
|
||||||
All expressions used in PL/pgSQL statements are processed
|
|
||||||
using the backends executor. Since even a constant looking
|
|
||||||
expression can have a totally different meaning for a
|
|
||||||
particular data type (as 'now' for abstime), it is impossible
|
|
||||||
for the PL/pgSQL parser to identify real constant values
|
|
||||||
other than the NULL keyword. The expressions are evaluated by
|
|
||||||
internally executing a query
|
|
||||||
|
|
||||||
SELECT <expr>
|
|
||||||
|
|
||||||
over the SPI manager. In the expression, occurences of
|
|
||||||
variable identifiers are substituted by parameters and the
|
|
||||||
actual values from the variables are passed to the executor
|
|
||||||
as query parameters. All the expressions used in a PL/pgSQL
|
|
||||||
function are only prepared and saved once.
|
|
||||||
|
|
||||||
If record fields are used in expressions or database
|
|
||||||
statements, the data types of the fields should not change
|
|
||||||
between calls of one and the same expression. Keep this in
|
|
||||||
mind when writing trigger procedures that handle events for
|
|
||||||
more than one table.
|
|
||||||
|
|
||||||
Statements
|
|
||||||
|
|
||||||
Anything not understood by the parser as specified below will
|
|
||||||
be put into a query and sent down to the database engine to
|
|
||||||
execute. The resulting query should not return any data
|
|
||||||
(insert, update, delete queries and all utility statements).
|
|
||||||
|
|
||||||
Assignment
|
|
||||||
|
|
||||||
An assignment of a value to a variable or rowtype field
|
|
||||||
is written as:
|
|
||||||
|
|
||||||
<identifier> := <expr>;
|
|
||||||
|
|
||||||
If the expressions result data type doesn't match the
|
|
||||||
variables data type, or the variables atttypmod value is
|
|
||||||
known (as for char(20)), the result value will be
|
|
||||||
implicitly casted by the PL/pgSQL executor using the
|
|
||||||
result types output- and the variables type input-
|
|
||||||
functions. Note that this could potentially result in
|
|
||||||
runtime errors generated by the types input functions.
|
|
||||||
|
|
||||||
An assignment of a complete selection into a record or
|
|
||||||
rowtype can be done as:
|
|
||||||
|
|
||||||
SELECT expressions INTO <target> FROM fromlist;
|
|
||||||
|
|
||||||
Target can be a record or rowtype variable, or a comma
|
|
||||||
separated list of variables and record/row fields.
|
|
||||||
|
|
||||||
If a rowtype or a variable list is used as target, the
|
|
||||||
selected values must exactly match the structure of the
|
|
||||||
target(s) or a runtime error occurs. The fromlist can be
|
|
||||||
followed by any valid qualification, grouping, sorting
|
|
||||||
etc.
|
|
||||||
|
|
||||||
There is a special condition [NOT] FOUND that can be used
|
|
||||||
immediately after a SELECT INTO to check if the data has
|
|
||||||
been found.
|
|
||||||
|
|
||||||
SELECT * INTO myrec FROM EMP WHERE empname = myname;
|
|
||||||
IF NOT FOUND THEN
|
|
||||||
RAISE EXCEPTION 'employee % not found', myname;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
If the selection returns multiple rows, only the first is
|
|
||||||
moved into the target fields. All others are discarded.
|
|
||||||
|
|
||||||
|
|
||||||
Calling another function
|
|
||||||
|
|
||||||
If a function should be called, this is normally done by
|
|
||||||
a SELECT query. But there are cases where someone isn't
|
|
||||||
interested in the functions result.
|
|
||||||
|
|
||||||
PERFORM querystring;
|
|
||||||
|
|
||||||
executes a 'SELECT querystring' over the SPI manager and
|
|
||||||
discards the result.
|
|
||||||
|
|
||||||
|
|
||||||
Returning from the function
|
|
||||||
|
|
||||||
RETURN <expr>;
|
|
||||||
|
|
||||||
The function terminates and the value of <expr> will be
|
|
||||||
returned to the upper executor. The return value of a
|
|
||||||
function cannot be undefined. If control reaches the end
|
|
||||||
of the toplevel block of the function without hitting a
|
|
||||||
RETURN statement, a runtime error will occur.
|
|
||||||
|
|
||||||
|
|
||||||
Aborting and messages
|
|
||||||
|
|
||||||
As indicated above there is an RAISE statement that can
|
|
||||||
throw messages into the PostgreSQL elog mechanism.
|
|
||||||
|
|
||||||
RAISE level 'format' [, identifier [...]];
|
|
||||||
|
|
||||||
Inside the format, % can be used as a placeholder for the
|
|
||||||
following, comma separated identifiers. The identifiers
|
|
||||||
must specify an existing variable or row/record field.
|
|
||||||
|
|
||||||
|
|
||||||
Conditionals
|
|
||||||
|
|
||||||
IF <expr> THEN
|
|
||||||
-- statements
|
|
||||||
[ELSE
|
|
||||||
-- statements]
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
The expression <expr> must return a value that at least
|
|
||||||
can be casted into a boolean.
|
|
||||||
|
|
||||||
|
|
||||||
Loops
|
|
||||||
|
|
||||||
There are multiple types of loops.
|
|
||||||
|
|
||||||
[<<label>>]
|
|
||||||
LOOP
|
|
||||||
-- statements
|
|
||||||
END LOOP;
|
|
||||||
|
|
||||||
An unconditional loop that must be terminated explicitly
|
|
||||||
by an EXIT statement. The optional label can be used by
|
|
||||||
EXIT statements of nested loops to specify which level of
|
|
||||||
nesting should be terminated.
|
|
||||||
|
|
||||||
[<<label>>]
|
|
||||||
WHILE <expr> LOOP
|
|
||||||
-- statements
|
|
||||||
END LOOP;
|
|
||||||
|
|
||||||
A conditional loop that is executed as long as the
|
|
||||||
evaluation of <expr> returns true.
|
|
||||||
|
|
||||||
[<<label>>]
|
|
||||||
FOR <name> IN [REVERSE] <expr>..<expr> LOOP
|
|
||||||
-- statements
|
|
||||||
END LOOP.
|
|
||||||
|
|
||||||
A loop that iterates over a range of integer values. The
|
|
||||||
variable <name> is automatically created as type integer
|
|
||||||
and exists only inside the loop. The two expressions
|
|
||||||
giving the lower and upper bound of the range are
|
|
||||||
evaluated only when entering the loop. The iteration step
|
|
||||||
is 1.
|
|
||||||
|
|
||||||
FOR <recname|rowname> IN <select_clause> LOOP
|
|
||||||
-- statements
|
|
||||||
END LOOP;
|
|
||||||
|
|
||||||
The record or row is assigned all the rows resulting from
|
|
||||||
the select clause and the statements executed for each.
|
|
||||||
If the loop is terminated with an EXIT statement, the
|
|
||||||
last accessed row is still accessible in the record or
|
|
||||||
rowtype.
|
|
||||||
|
|
||||||
EXIT [label] [WHEN <expr>];
|
|
||||||
|
|
||||||
If no label given, the innermost loop is terminated and
|
|
||||||
the statement following END LOOP is executed next. If
|
|
||||||
label is given, it must be the label of the current or an
|
|
||||||
upper level of nested loops or blocks. Then the named
|
|
||||||
loop or block is terminated and control continues with
|
|
||||||
the statement after the loops/blocks corresponding END.
|
|
||||||
|
|
||||||
Trigger procedures
|
|
||||||
|
|
||||||
PL/pgSQL can also be used to define trigger procedures. They
|
|
||||||
are created using CREATE FUNCTION as a function with no
|
|
||||||
arguments and a return type of opaque.
|
|
||||||
|
|
||||||
There are some PostgreSQL specific details in functions used
|
|
||||||
as trigger procedures.
|
|
||||||
|
|
||||||
First they have some special variables created above the
|
|
||||||
toplevel statement block. These are:
|
|
||||||
|
|
||||||
new (record)
|
|
||||||
The new database tuple on INSERT/UPDATE operations at
|
|
||||||
ROW level.
|
|
||||||
|
|
||||||
old (record)
|
|
||||||
The old database tuple on UPDATE/DELETE operations at
|
|
||||||
ROW level.
|
|
||||||
|
|
||||||
tg_name (type name)
|
|
||||||
The triggers name from pg_trigger.
|
|
||||||
|
|
||||||
tg_when (type text)
|
|
||||||
A string of either 'BEFORE' or 'AFTER' depending on
|
|
||||||
the triggers definition.
|
|
||||||
|
|
||||||
tg_level (type text)
|
|
||||||
A string of either 'ROW' or 'STATEMENT' depending on
|
|
||||||
the triggers definition.
|
|
||||||
|
|
||||||
tg_op (type text)
|
|
||||||
A string of 'INSERT', 'UPDATE' or 'DELETE' telling
|
|
||||||
for which operation the trigger is actually fired.
|
|
||||||
|
|
||||||
tg_relid (type oid)
|
|
||||||
The Oid of the relation for which the trigger is
|
|
||||||
actually fired.
|
|
||||||
|
|
||||||
tg_relname (type name)
|
|
||||||
The relations name for which the trigger is actually
|
|
||||||
fired.
|
|
||||||
|
|
||||||
tg_nargs (type integer)
|
|
||||||
The number of arguments given to the trigger
|
|
||||||
procedure in the CREATE TRIGGER statement.
|
|
||||||
|
|
||||||
tg_argv[] (types text)
|
|
||||||
The arguments from the CREATE TRIGGER statement. The
|
|
||||||
index counts from 0 and can be given as expression.
|
|
||||||
Invalid indices (< 0 or >= tg_nargs) result in a NULL
|
|
||||||
value.
|
|
||||||
|
|
||||||
Second, they must return either NULL, or a record/rowtype
|
|
||||||
containing exactly the structure of the table the trigger was
|
|
||||||
fired for. Triggers fired AFTER might allways return NULL
|
|
||||||
with no effect. Triggers fired BEFORE signal the trigger
|
|
||||||
manager to skip the operation for this actual row when
|
|
||||||
returning NULL. Otherwise, the returned record/rowtype
|
|
||||||
replaces the inserted/updated tuple in the operation. It is
|
|
||||||
possible to replace single values directly in new and return
|
|
||||||
that, or to build a complete new record/rowtype to return.
|
|
||||||
|
|
||||||
Exceptions
|
|
||||||
|
|
||||||
PostgreSQL doesn't have a very smart exception handling
|
|
||||||
model. Whenever the parser, planner/optimizer or executor
|
|
||||||
decide that a statement cannot be processed any longer, the
|
|
||||||
whole transaction gets aborted and the the system jumps back
|
|
||||||
into the mainloop using longjmp() to get the next query from
|
|
||||||
the client application.
|
|
||||||
|
|
||||||
It is possible to hook into the longjmp() mechanism to notice
|
|
||||||
that this happens. But currently it's impossible to tell what
|
|
||||||
really caused the abort (input/output conversion error,
|
|
||||||
floating point error, parse error) And it's possible that the
|
|
||||||
backend is in an inconsistent state at this point so
|
|
||||||
returning to the upper executor or issuing more commands
|
|
||||||
might corrupt the whole database.
|
|
||||||
|
|
||||||
Thus, the only thing PL/pgSQL currently does when it
|
|
||||||
encounters an abort during execution of a function or trigger
|
|
||||||
procedure is to write some additional DEBUG log messages
|
|
||||||
telling in which function and where (line number and type of
|
|
||||||
statement) this happened.
|
|
||||||
|
|
||||||
This might change in the future.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user