much like a <literal>FOR</literal> loop,
but instead of iterating through the rows returned by an SQL query,
it iterates through the elements of an array value.
(In general, <literal>FOREACH</literal> is meant for looping through
components of a composite-valued expression; variants for looping
through composites besides arrays may be added in future.)
The <literal>FOREACH</literal> statement to loop over an array is:
<synopsis>
<optional> <<<replaceable>label</replaceable>>> </optional>
FOREACH <replaceable>target</replaceable> <optional> SLICE <replaceable>number</replaceable> </optional> IN ARRAY <replaceable>expression</replaceable> LOOP
<replaceable>statements</replaceable>
END LOOP <optional> <replaceable>label</replaceable> </optional>;
</synopsis>
</para>
<para>
Without <literal>SLICE</literal>, or if <literal>SLICE 0</literal> is specified,
the loop iterates through individual elements of the array produced
by evaluating the <replaceable>expression</replaceable>.
The <replaceable>target</replaceable> variable is assigned each
element value in sequence, and the loop body is executed for each element.
Here is an example of looping through the elements of an integer
array:
<programlisting>
CREATE FUNCTION sum(int[]) RETURNS int8 AS $$
DECLARE
s int8 := 0;
x int;
BEGIN
FOREACH x IN ARRAY $1
LOOP
s := s + x;
END LOOP;
RETURN s;
END;
$$ LANGUAGE plpgsql;
</programlisting>
The elements are visited in storage order, regardless of the number of
array dimensions. Although the <replaceable>target</replaceable> is
usually just a single variable, it can be a list of variables when
looping through an array of composite values (records). In that case,
for each array element, the variables are assigned from successive
columns of the composite value.
</para>
<para>
With a positive <literal>SLICE</literal> value, <literal>FOREACH</literal>
iterates through slices of the array rather than single elements.
The <literal>SLICE</literal> value must be an integer constant not larger
than the number of dimensions of the array. The
<replaceable>target</replaceable> variable must be an array,
and it receives successive slices of the array value, where each slice
is of the number of dimensions specified by <literal>SLICE</literal>.
Here is an example of iterating through one-dimensional slices:
<programlisting>
CREATE FUNCTION scan_rows(int[]) RETURNS void AS $$
DECLARE
x int[];
BEGIN
FOREACH x SLICE 1 IN ARRAY $1
LOOP
RAISE NOTICE 'row = %', x;
END LOOP;
END;
$$ LANGUAGE plpgsql;
SELECT scan_rows(ARRAY[[1,2,3],[4,5,6],[7,8,9],[10,11,12]]);
NOTICE: row = {1,2,3}
NOTICE: row = {4,5,6}
NOTICE: row = {7,8,9}
NOTICE: row = {10,11,12}
</programlisting>
</para>
</sect2>
<sect2 id="plpgsql-error-trapping">
<title>Trapping Errors</title>
<indexterm>
<primary>exceptions</primary>
<secondary>in PL/pgSQL</secondary>
</indexterm>
<para>
By default, any error occurring in a <application>PL/pgSQL</application>
function aborts execution of the function and the
surrounding transaction. You can trap errors and recover
from them by using a <command>BEGIN</command> block with an
<literal>EXCEPTION</literal> clause. The syntax is an extension of the
normal syntax for a <command>BEGIN</command> block:
<synopsis>
<optional> <<<replaceable>label</replaceable>>> </optional>
<optional> DECLARE
<replaceable>declarations</replaceable> </optional>
BEGIN
<replaceable>statements</replaceable>
EXCEPTION
WHEN <replaceable>condition</replaceable> <optional> OR <replaceable>condition</replaceable> ... </optional> THEN
<replaceable>handler_statements</replaceable>
<optional> WHEN <replaceable>condition</replaceable> <optional> OR <replaceable>condition</replaceable> ...