|
1 | 1 | <!--
|
2 |
| -$PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.41 2004/07/11 23:26:51 momjian Exp $ |
| 2 | +$PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.42 2004/07/31 07:39:17 tgl Exp $ |
3 | 3 | -->
|
4 | 4 |
|
5 | 5 | <chapter id="plpgsql">
|
@@ -1796,6 +1796,101 @@ END LOOP;
|
1796 | 1796 | rather than the simple syntax error one might expect to get.
|
1797 | 1797 | </para>
|
1798 | 1798 | </note>
|
| 1799 | + </sect2> |
| 1800 | + |
| 1801 | + <sect2 id="plpgsql-error-trapping"> |
| 1802 | + <title>Trapping Errors</title> |
| 1803 | + |
| 1804 | + <para> |
| 1805 | + By default, any error occurring in a <application>PL/pgSQL</> |
| 1806 | + function aborts execution of the function, and indeed of the |
| 1807 | + surrounding transaction as well. You can trap errors and recover |
| 1808 | + from them by using a <command>BEGIN</> block with an |
| 1809 | + <literal>EXCEPTION</> clause. The syntax is an extension of the |
| 1810 | + normal syntax for a <command>BEGIN</> block: |
| 1811 | + |
| 1812 | +<synopsis> |
| 1813 | +<optional> <<<replaceable>label</replaceable>>> </optional> |
| 1814 | +<optional> DECLARE |
| 1815 | + <replaceable>declarations</replaceable> </optional> |
| 1816 | +BEGIN |
| 1817 | + <replaceable>statements</replaceable> |
| 1818 | +EXCEPTION |
| 1819 | + WHEN <replaceable>condition</replaceable> THEN |
| 1820 | + <replaceable>handler_statements</replaceable> |
| 1821 | + <optional> WHEN <replaceable>condition</replaceable> THEN |
| 1822 | + <replaceable>handler_statements</replaceable> |
| 1823 | + ... |
| 1824 | + </optional> |
| 1825 | +END; |
| 1826 | +</synopsis> |
| 1827 | + </para> |
| 1828 | + |
| 1829 | + <para> |
| 1830 | + If no error occurs, this form of block simply executes all the |
| 1831 | + <replaceable>statements</replaceable>, and then control passes |
| 1832 | + to the next statement after <literal>END</>. But if an error |
| 1833 | + occurs within the <replaceable>statements</replaceable>, further |
| 1834 | + processing of the <replaceable>statements</replaceable> is |
| 1835 | + abandoned, and control passes to the <literal>EXCEPTION</> list. |
| 1836 | + The list is searched for the first <replaceable>condition</replaceable> |
| 1837 | + matching the error that occurred. If a match is found, the |
| 1838 | + corresponding <replaceable>handler_statements</replaceable> are |
| 1839 | + executed, and then control passes to the next statement after |
| 1840 | + <literal>END</>. If no match is found, the error propagates out |
| 1841 | + as though the <literal>EXCEPTION</> clause were not there at all: |
| 1842 | + the error can be caught by an enclosing block with |
| 1843 | + <literal>EXCEPTION</>, or if there is none it aborts processing |
| 1844 | + of the function. The special condition name <literal>OTHERS</> |
| 1845 | + matches every error type except <literal>QUERY_CANCELED</>. |
| 1846 | + (It is possible, but usually not a good idea, to trap |
| 1847 | + <literal>QUERY_CANCELED</> by name.) |
| 1848 | + </para> |
| 1849 | + |
| 1850 | + <para> |
| 1851 | + If a new error occurs within the selected |
| 1852 | + <replaceable>handler_statements</replaceable>, it cannot be caught |
| 1853 | + by this <literal>EXCEPTION</> clause, but is propagated out. |
| 1854 | + A surrounding <literal>EXCEPTION</> clause could catch it. |
| 1855 | + </para> |
| 1856 | + |
| 1857 | + <para> |
| 1858 | + When an error is caught by an <literal>EXCEPTION</> clause, |
| 1859 | + the local variables of the <application>PL/pgSQL</> function |
| 1860 | + remain as they were when the error occurred, but all changes |
| 1861 | + to persistent database state within the block are rolled back. |
| 1862 | + As an example, consider this fragment: |
| 1863 | + |
| 1864 | +<programlisting> |
| 1865 | + INSERT INTO mytab(firstname, lastname) VALUES('Tom', 'Jones'); |
| 1866 | + BEGIN |
| 1867 | + UPDATE mytab SET firstname = 'Joe' WHERE lastname = 'Jones'; |
| 1868 | + x := x + 1; |
| 1869 | + y := x / 0; |
| 1870 | + EXCEPTION |
| 1871 | + WHEN division_by_zero THEN |
| 1872 | + RAISE NOTICE 'caught division_by_zero'; |
| 1873 | + RETURN x; |
| 1874 | + END; |
| 1875 | +</programlisting> |
| 1876 | + |
| 1877 | + When control reaches the assignment to <literal>y</>, it will |
| 1878 | + fail with a <literal>division_by_zero</> error. This will be caught by |
| 1879 | + the <literal>EXCEPTION</> clause. The value returned in the |
| 1880 | + <command>RETURN</> statement will be the incremented value of |
| 1881 | + <literal>x</>, but the effects of the <command>UPDATE</> command will |
| 1882 | + have been rolled back. The <command>INSERT</> command is not rolled |
| 1883 | + back, however, so the end result is that the database contains |
| 1884 | + <literal>Tom Jones</> not <literal>Joe Jones</>. |
| 1885 | + </para> |
| 1886 | + |
| 1887 | + <tip> |
| 1888 | + <para> |
| 1889 | + A block containing an <literal>EXCEPTION</> clause is significantly |
| 1890 | + more expensive to enter and exit than a block without one. Therefore, |
| 1891 | + don't use <literal>EXCEPTION</> without need. |
| 1892 | + </para> |
| 1893 | + </tip> |
1799 | 1894 | </sect2>
|
1800 | 1895 | </sect1>
|
1801 | 1896 |
|
@@ -2120,11 +2215,11 @@ RAISE <replaceable class="parameter">level</replaceable> '<replaceable class="pa
|
2120 | 2215 | </synopsis>
|
2121 | 2216 |
|
2122 | 2217 | Possible levels are <literal>DEBUG</literal>,
|
2123 |
| - <literal>LOG</literal>, |
| 2218 | + <literal>LOG</literal>, <literal>INFO</literal>, |
2124 | 2219 | <literal>NOTICE</literal>, <literal>WARNING</literal>,
|
2125 | 2220 | and <literal>EXCEPTION</literal>.
|
2126 |
| - <literal>EXCEPTION</literal> raises an errorandaborts the current |
2127 |
| - transaction; the other levels only generate messages of different |
| 2221 | + <literal>EXCEPTION</literal> raises an error(which normallyaborts the |
| 2222 | +currenttransaction); the other levels only generate messages of different |
2128 | 2223 | priority levels.
|
2129 | 2224 | Whether messages of a particular priority are reported to the client,
|
2130 | 2225 | written to the server log, or both is controlled by the
|
@@ -2164,28 +2259,11 @@ RAISE EXCEPTION 'Nonexistent ID --> %', user_id;
|
2164 | 2259 | </para>
|
2165 | 2260 |
|
2166 | 2261 | <para>
|
2167 |
| - <productname>PostgreSQL</productname> does not have a very smart |
2168 |
| - exception handling model. Whenever the parser, planner/optimizer |
2169 |
| - or executor decide that a statement cannot be processed any longer, |
2170 |
| - the whole transaction gets aborted and the system jumps back |
2171 |
| - into the main loop to get the next command from the client application. |
2172 |
| - </para> |
2173 |
| - |
2174 |
| - <para> |
2175 |
| - It is possible to hook into the error mechanism to notice that this |
2176 |
| - happens. But currently it is impossible to tell what really |
2177 |
| - caused the abort (data type format error, floating-point |
2178 |
| - error, parse error, etc.). And it is possible that the database server |
2179 |
| - is in an inconsistent state at this point so returning to the upper |
2180 |
| - executor or issuing more commands might corrupt the whole database. |
2181 |
| - </para> |
2182 |
| - |
2183 |
| - <para> |
2184 |
| - Thus, the only thing <application>PL/pgSQL</application> |
2185 |
| - currently does when it encounters an abort during execution of a |
2186 |
| - function or trigger procedure is to add some fields to the message |
2187 |
| - telling in which function and where (line number and type of statement) |
2188 |
| - the error happened. The error always stops execution of the function. |
| 2262 | + <command>RAISE EXCEPTION</command> presently always generates |
| 2263 | + the same SQLSTATE code, <literal>P0001</>, no matter what message |
| 2264 | + it is invoked with. It is possible to trap this exception with |
| 2265 | + <literal>EXCEPTION ... WHEN RAISE_EXCEPTION THEN ...</> but there |
| 2266 | + is no way to tell one <command>RAISE</> from another. |
2189 | 2267 | </para>
|
2190 | 2268 | </sect1>
|
2191 | 2269 |
|
|