<programlisting>
CREATE PROCEDURE transaction_test2()
LANGUAGE plpgsql
AS $$
DECLARE
r RECORD;
BEGIN
FOR r IN SELECT * FROM test2 ORDER BY x LOOP
INSERT INTO test1 (a) VALUES (r.x);
COMMIT;
END LOOP;
END;
$$;
CALL transaction_test2();
</programlisting>
Normally, cursors are automatically closed at transaction commit.
However, a cursor created as part of a loop like this is automatically
converted to a holdable cursor by the first <command>COMMIT</command> or
<command>ROLLBACK</command>. That means that the cursor is fully
evaluated at the first <command>COMMIT</command> or
<command>ROLLBACK</command> rather than row by row. The cursor is still
removed automatically after the loop, so this is mostly invisible to the
user. But one must keep in mind that any table or row locks taken by
the cursor's query will no longer be held after the
first <command>COMMIT</command> or
<command>ROLLBACK</command>.
</para>
<para>
Transaction commands are not allowed in cursor loops driven by commands
that are not read-only (for example <command>UPDATE
... RETURNING</command>).
</para>
</sect1>
<sect1 id="plpgsql-errors-and-messages">
<title>Errors and Messages</title>
<sect2 id="plpgsql-statements-raise">
<title>Reporting Errors and Messages</title>
<indexterm>
<primary>RAISE</primary>
<secondary>in PL/pgSQL</secondary>
</indexterm>
<indexterm>
<primary>reporting errors</primary>
<secondary>in PL/pgSQL</secondary>
</indexterm>
<para>
Use the <command>RAISE</command> statement to report messages and
raise errors.
<synopsis>
RAISE <optional> <replaceable class="parameter">level</replaceable> </optional> '<replaceable class="parameter">format</replaceable>' <optional>, <replaceable class="parameter">expression</replaceable> <optional>, ... </optional></optional> <optional> USING <replaceable class="parameter">option</replaceable> { = | := } <replaceable class="parameter">expression</replaceable> <optional>, ... </optional> </optional>;
RAISE <optional> <replaceable class="parameter">level</replaceable> </optional> <replaceable class="parameter">condition_name</replaceable> <optional> USING <replaceable class="parameter">option</replaceable> { = | := } <replaceable class="parameter">expression</replaceable> <optional>, ... </optional> </optional>;
RAISE <optional> <replaceable class="parameter">level</replaceable> </optional> SQLSTATE '<replaceable class="parameter">sqlstate</replaceable>' <optional> USING <replaceable class="parameter">option</replaceable> { = | := } <replaceable class="parameter">expression</replaceable> <optional>, ... </optional> </optional>;
RAISE <optional> <replaceable class="parameter">level</replaceable> </optional> USING <replaceable class="parameter">option</replaceable> { = | := } <replaceable class="parameter">expression</replaceable> <optional>, ... </optional>;
RAISE ;
</synopsis>
The <replaceable class="parameter">level</replaceable> option specifies
the error severity. Allowed levels are <literal>DEBUG</literal>,
<literal>LOG</literal>, <literal>INFO</literal>,
<literal>NOTICE</literal>, <literal>WARNING</literal>,
and <literal>EXCEPTION</literal>, with <literal>EXCEPTION</literal>
being the default.
<literal>EXCEPTION</literal> raises an error (which normally aborts the
current transaction); the other levels only generate messages of different
priority levels.
Whether messages of a particular priority are reported to the client,
written to the server log, or both is controlled by the
<xref linkend="guc-log-min-messages"/> and
<xref linkend="guc-client-min-messages"/> configuration
variables. See <xref linkend="runtime-config"/> for more
information.
</para>
<para>
In the first syntax variant,
after the <replaceable class="parameter">level</replaceable> if any,
write a <replaceable class="parameter">format</replaceable>