EXECUTE FUNCTION tclsnitch();
</programlisting>
</para>
</sect1>
<sect1 id="pltcl-error-handling">
<title>Error Handling in PL/Tcl</title>
<indexterm>
<primary>exceptions</primary>
<secondary>in PL/Tcl</secondary>
</indexterm>
<para>
Tcl code within or called from a PL/Tcl function can raise an error,
either by executing some invalid operation or by generating an error
using the Tcl <function>error</function> command or
PL/Tcl's <function>elog</function> command. Such errors can be caught
within Tcl using the Tcl <function>catch</function> command. If an
error is not caught but is allowed to propagate out to the top level of
execution of the PL/Tcl function, it is reported as an SQL error in the
function's calling query.
</para>
<para>
Conversely, SQL errors that occur within PL/Tcl's
<function>spi_exec</function>, <function>spi_prepare</function>,
and <function>spi_execp</function> commands are reported as Tcl errors,
so they are catchable by Tcl's <function>catch</function> command.
(Each of these PL/Tcl commands runs its SQL operation in a
subtransaction, which is rolled back on error, so that any
partially-completed operation is automatically cleaned up.)
Again, if an error propagates out to the top level without being caught,
it turns back into an SQL error.
</para>
<para>
Tcl provides an <varname>errorCode</varname> variable that can represent
additional information about an error in a form that is easy for Tcl
programs to interpret. The contents are in Tcl list format, and the
first word identifies the subsystem or library reporting the error;
beyond that the contents are left to the individual subsystem or
library. For database errors reported by PL/Tcl commands, the first
word is <literal>POSTGRES</literal>, the second word is the PostgreSQL
version number, and additional words are field name/value pairs
providing detailed information about the error.
Fields <varname>SQLSTATE</varname>, <varname>condition</varname>,
and <varname>message</varname> are always supplied
(the first two represent the error code and condition name as shown
in <xref linkend="errcodes-appendix"/>).
Fields that may be present include
<varname>detail</varname>, <varname>hint</varname>, <varname>context</varname>,
<varname>schema</varname>, <varname>table</varname>, <varname>column</varname>,
<varname>datatype</varname>, <varname>constraint</varname>,
<varname>statement</varname>, <varname>cursor_position</varname>,
<varname>filename</varname>, <varname>lineno</varname>, and
<varname>funcname</varname>.
</para>
<para>
A convenient way to work with PL/Tcl's <varname>errorCode</varname>
information is to load it into an array, so that the field names become
array subscripts. Code for doing that might look like
<programlisting>
if {[catch { spi_exec $sql_command }]} {
if {[lindex $::errorCode 0] == "POSTGRES"} {
array set errorArray $::errorCode
if {$errorArray(condition) == "undefined_table"} {
# deal with missing table
} else {
# deal with some other type of SQL error
}
}
}
</programlisting>
(The double colons explicitly specify that <varname>errorCode</varname>
is a global variable.)
</para>
</sect1>
<sect1 id="pltcl-subtransactions">
<title>Explicit Subtransactions in PL/Tcl</title>
<indexterm>
<primary>subtransactions</primary>
<secondary>in PL/Tcl</secondary>
</indexterm>
<para>
Recovering from errors caused by database access as described in
<xref linkend="pltcl-error-handling"/> can lead to an undesirable
situation where some operations succeed before one of them fails,
and after recovering from that error the data is left in an
inconsistent