Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 3d4890c

Browse files
committed
Add GET STACKED DIAGNOSTICS plpgsql command to retrieve exception info.
This is more SQL-spec-compliant, more easily extensible, and better performing than the old method of inventing special variables. Pavel Stehule, reviewed by Shigeru Hanada and David Wheeler
1 parent 3406dd2 commit 3d4890c

File tree

9 files changed

+480
-66
lines changed

9 files changed

+480
-66
lines changed

doc/src/sgml/plpgsql.sgml

+106-15
Original file line numberDiff line numberDiff line change
@@ -1387,11 +1387,11 @@ EXECUTE format('UPDATE tbl SET %I = $1 WHERE key = $2', colname)
13871387
command, which has the form:
13881388

13891389
<synopsis>
1390-
GET DIAGNOSTICS <replaceable>variable</replaceable> = <replaceable>item</replaceable> <optional> , ... </optional>;
1390+
GET <optional> CURRENT </optional> DIAGNOSTICS <replaceable>variable</replaceable> = <replaceable>item</replaceable> <optional> , ... </optional>;
13911391
</synopsis>
13921392

13931393
This command allows retrieval of system status indicators. Each
1394-
<replaceable>item</replaceable> is a key word identifying a state
1394+
<replaceable>item</replaceable> is a key word identifying a status
13951395
value to be assigned to the specified variable (which should be
13961396
of the right data type to receive it). The currently available
13971397
status items are <varname>ROW_COUNT</>, the number of rows
@@ -2522,16 +2522,6 @@ END;
25222522
</para>
25232523
</tip>
25242524

2525-
<para>
2526-
Within an exception handler, the <varname>SQLSTATE</varname>
2527-
variable contains the error code that corresponds to the
2528-
exception that was raised (refer to <xref
2529-
linkend="errcodes-table"> for a list of possible error
2530-
codes). The <varname>SQLERRM</varname> variable contains the
2531-
error message associated with the exception. These variables are
2532-
undefined outside exception handlers.
2533-
</para>
2534-
25352525
<example id="plpgsql-upsert-example">
25362526
<title>Exceptions with <command>UPDATE</>/<command>INSERT</></title>
25372527
<para>
@@ -2568,11 +2558,112 @@ LANGUAGE plpgsql;
25682558
SELECT merge_db(1, 'david');
25692559
SELECT merge_db(1, 'dennis');
25702560
</programlisting>
2571-
This example assumes the <literal>unique_violation</> error is caused by
2572-
the <command>INSERT</>, and not by an <command>INSERT</> trigger function
2573-
on the table.
2561+
2562+
This coding assumes the <literal>unique_violation</> error is caused by
2563+
the <command>INSERT</>, and not by, say, an <command>INSERT</> in a
2564+
trigger function on the table. More safety could be had by using the
2565+
features discussed next to check that the trapped error was the one
2566+
expected.
25742567
</para>
25752568
</example>
2569+
2570+
<sect3 id="plpgsql-exception-diagnostics">
2571+
<title>Obtaining information about an error</title>
2572+
2573+
<para>
2574+
Exception handlers frequently need to identify the specific error that
2575+
occurred. There are two ways to get information about the current
2576+
exception in <application>PL/pgSQL</>: special variables and the
2577+
<command>GET STACKED DIAGNOSTICS</command> command.
2578+
</para>
2579+
2580+
<para>
2581+
Within an exception handler, the special variable
2582+
<varname>SQLSTATE</varname> contains the error code that corresponds to
2583+
the exception that was raised (refer to <xref linkend="errcodes-table">
2584+
for a list of possible error codes). The special variable
2585+
<varname>SQLERRM</varname> contains the error message associated with the
2586+
exception. These variables are undefined outside exception handlers.
2587+
</para>
2588+
2589+
<para>
2590+
Within an exception handler, one may also retrieve
2591+
information about the current exception by using the
2592+
<command>GET STACKED DIAGNOSTICS</command> command, which has the form:
2593+
2594+
<synopsis>
2595+
GET STACKED DIAGNOSTICS <replaceable>variable</replaceable> = <replaceable>item</replaceable> <optional> , ... </optional>;
2596+
</synopsis>
2597+
2598+
Each <replaceable>item</replaceable> is a key word identifying a status
2599+
value to be assigned to the specified variable (which should be
2600+
of the right data type to receive it). The currently available
2601+
status items are:
2602+
2603+
<table id="plpgsql-exception-diagnostics-values">
2604+
<title>Error diagnostics values</title>
2605+
<tgroup cols="3">
2606+
<thead>
2607+
<row>
2608+
<entry>Name</entry>
2609+
<entry>Type</entry>
2610+
<entry>Description</entry>
2611+
</row>
2612+
</thead>
2613+
<tbody>
2614+
<row>
2615+
<entry><literal>RETURNED_SQLSTATE</literal></entry>
2616+
<entry>text</entry>
2617+
<entry>the SQLSTATE error code of the exception</entry>
2618+
</row>
2619+
<row>
2620+
<entry><literal>MESSAGE_TEXT</literal></entry>
2621+
<entry>text</entry>
2622+
<entry>the text of the exception's primary message</entry>
2623+
</row>
2624+
<row>
2625+
<entry><literal>PG_EXCEPTION_DETAIL</literal></entry>
2626+
<entry>text</entry>
2627+
<entry>the text of the exception's detail message, if any</entry>
2628+
</row>
2629+
<row>
2630+
<entry><literal>PG_EXCEPTION_HINT</literal></entry>
2631+
<entry>text</entry>
2632+
<entry>the text of the exception's hint message, if any</entry>
2633+
</row>
2634+
<row>
2635+
<entry><literal>PG_EXCEPTION_CONTEXT</literal></entry>
2636+
<entry>text</entry>
2637+
<entry>line(s) of text describing the call stack</entry>
2638+
</row>
2639+
</tbody>
2640+
</tgroup>
2641+
</table>
2642+
</para>
2643+
2644+
<para>
2645+
If the exception did not set a value for an item, an empty string
2646+
will be returned.
2647+
</para>
2648+
2649+
<para>
2650+
Here is an example:
2651+
<programlisting>
2652+
DECLARE
2653+
text_var1 text;
2654+
text_var2 text;
2655+
text_var3 text;
2656+
BEGIN
2657+
-- some processing which might cause an exception
2658+
...
2659+
EXCEPTION WHEN OTHERS THEN
2660+
GET STACKED DIAGNOSTICS text_var1 = MESSAGE_TEXT,
2661+
text_var2 = PG_EXCEPTION_DETAIL,
2662+
text_var3 = PG_EXCEPTION_HINT;
2663+
END;
2664+
</programlisting>
2665+
</para>
2666+
</sect3>
25762667
</sect2>
25772668
</sect1>
25782669

src/backend/utils/errcodes.txt

+31-24
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@
5151
# class (the first two characters of the code value identify the class).
5252
# The listing is organized by class to make this prominent.
5353
#
54-
# The generic '000' subclass code should be used for an error only
54+
# Each class should have a generic '000' subclass. However,
55+
# the generic '000' subclass code should be used for an error only
5556
# when there is not a more-specific subclass code defined.
5657
#
5758
# The SQL spec requires that all the elements of a SQLSTATE code be
@@ -132,6 +133,11 @@ Section: Class 0P - Invalid Role Specification
132133

133134
0P000 E ERRCODE_INVALID_ROLE_SPECIFICATION invalid_role_specification
134135

136+
Section: Class 0Z - Diagnostics Exception
137+
138+
0Z000 E ERRCODE_DIAGNOSTICS_EXCEPTION diagnostics_exception
139+
0Z002 E ERRCODE_STACKED_DIAGNOSTICS_ACCESSED_WITHOUT_ACTIVE_HANDLER stacked_diagnostics_accessed_without_active_handler
140+
135141
Section: Class 20 - Case Not Found
136142

137143
20000 E ERRCODE_CASE_NOT_FOUND case_not_found
@@ -399,6 +405,7 @@ Section: Class 57 - Operator Intervention
399405
Section: Class 58 - System Error (errors external to PostgreSQL itself)
400406

401407
# (class borrowed from DB2)
408+
58000 E ERRCODE_SYSTEM_ERROR system_error
402409
58030 E ERRCODE_IO_ERROR io_error
403410
58P01 E ERRCODE_UNDEFINED_FILE undefined_file
404411
58P02 E ERRCODE_DUPLICATE_FILE duplicate_file
@@ -415,30 +422,30 @@ Section: Class HV - Foreign Data Wrapper Error (SQL/MED)
415422
HV000 E ERRCODE_FDW_ERROR fdw_error
416423
HV005 E ERRCODE_FDW_COLUMN_NAME_NOT_FOUND fdw_column_name_not_found
417424
HV002 E ERRCODE_FDW_DYNAMIC_PARAMETER_VALUE_NEEDED fdw_dynamic_parameter_value_needed
418-
HV010 E ERRCODE_FDW_FUNCTION_SEQUENCE_ERROR fdw_function_sequence_error
425+
HV010 E ERRCODE_FDW_FUNCTION_SEQUENCE_ERROR fdw_function_sequence_error
419426
HV021 E ERRCODE_FDW_INCONSISTENT_DESCRIPTOR_INFORMATION fdw_inconsistent_descriptor_information
420-
HV024 E ERRCODE_FDW_INVALID_ATTRIBUTE_VALUE fdw_invalid_attribute_value
421-
HV007 E ERRCODE_FDW_INVALID_COLUMN_NAME fdw_invalid_column_name
422-
HV008 E ERRCODE_FDW_INVALID_COLUMN_NUMBER fdw_invalid_column_number
423-
HV004 E ERRCODE_FDW_INVALID_DATA_TYPE fdw_invalid_data_type
424-
HV006 E ERRCODE_FDW_INVALID_DATA_TYPE_DESCRIPTORS fdw_invalid_data_type_descriptors
425-
HV091 E ERRCODE_FDW_INVALID_DESCRIPTOR_FIELD_IDENTIFIER fdw_invalid_descriptor_field_identifier
426-
HV00B E ERRCODE_FDW_INVALID_HANDLE fdw_invalid_handle
427-
HV00C E ERRCODE_FDW_INVALID_OPTION_INDEX fdw_invalid_option_index
428-
HV00D E ERRCODE_FDW_INVALID_OPTION_NAME fdw_invalid_option_name
429-
HV090 E ERRCODE_FDW_INVALID_STRING_LENGTH_OR_BUFFER_LENGTH fdw_invalid_string_length_or_buffer_length
430-
HV00A E ERRCODE_FDW_INVALID_STRING_FORMAT fdw_invalid_string_format
431-
HV009 E ERRCODE_FDW_INVALID_USE_OF_NULL_POINTER fdw_invalid_use_of_null_pointer
432-
HV014 E ERRCODE_FDW_TOO_MANY_HANDLES fdw_too_many_handles
433-
HV001 E ERRCODE_FDW_OUT_OF_MEMORY fdw_out_of_memory
434-
HV00P E ERRCODE_FDW_NO_SCHEMAS fdw_no_schemas
435-
HV00J E ERRCODE_FDW_OPTION_NAME_NOT_FOUND fdw_option_name_not_found
436-
HV00K E ERRCODE_FDW_REPLY_HANDLE fdw_reply_handle
437-
HV00Q E ERRCODE_FDW_SCHEMA_NOT_FOUND fdw_schema_not_found
438-
HV00R E ERRCODE_FDW_TABLE_NOT_FOUND fdw_table_not_found
439-
HV00L E ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION fdw_unable_to_create_execution
440-
HV00M E ERRCODE_FDW_UNABLE_TO_CREATE_REPLY fdw_unable_to_create_reply
441-
HV00N E ERRCODE_FDW_UNABLE_TO_ESTABLISH_CONNECTION fdw_unable_to_establish_connection
427+
HV024 E ERRCODE_FDW_INVALID_ATTRIBUTE_VALUE fdw_invalid_attribute_value
428+
HV007 E ERRCODE_FDW_INVALID_COLUMN_NAME fdw_invalid_column_name
429+
HV008 E ERRCODE_FDW_INVALID_COLUMN_NUMBER fdw_invalid_column_number
430+
HV004 E ERRCODE_FDW_INVALID_DATA_TYPE fdw_invalid_data_type
431+
HV006 E ERRCODE_FDW_INVALID_DATA_TYPE_DESCRIPTORS fdw_invalid_data_type_descriptors
432+
HV091 E ERRCODE_FDW_INVALID_DESCRIPTOR_FIELD_IDENTIFIER fdw_invalid_descriptor_field_identifier
433+
HV00B E ERRCODE_FDW_INVALID_HANDLE fdw_invalid_handle
434+
HV00C E ERRCODE_FDW_INVALID_OPTION_INDEX fdw_invalid_option_index
435+
HV00D E ERRCODE_FDW_INVALID_OPTION_NAME fdw_invalid_option_name
436+
HV090 E ERRCODE_FDW_INVALID_STRING_LENGTH_OR_BUFFER_LENGTH fdw_invalid_string_length_or_buffer_length
437+
HV00A E ERRCODE_FDW_INVALID_STRING_FORMAT fdw_invalid_string_format
438+
HV009 E ERRCODE_FDW_INVALID_USE_OF_NULL_POINTER fdw_invalid_use_of_null_pointer
439+
HV014 E ERRCODE_FDW_TOO_MANY_HANDLES fdw_too_many_handles
440+
HV001 E ERRCODE_FDW_OUT_OF_MEMORY fdw_out_of_memory
441+
HV00P E ERRCODE_FDW_NO_SCHEMAS fdw_no_schemas
442+
HV00J E ERRCODE_FDW_OPTION_NAME_NOT_FOUND fdw_option_name_not_found
443+
HV00K E ERRCODE_FDW_REPLY_HANDLE fdw_reply_handle
444+
HV00Q E ERRCODE_FDW_SCHEMA_NOT_FOUND fdw_schema_not_found
445+
HV00R E ERRCODE_FDW_TABLE_NOT_FOUND fdw_table_not_found
446+
HV00L E ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION fdw_unable_to_create_execution
447+
HV00M E ERRCODE_FDW_UNABLE_TO_CREATE_REPLY fdw_unable_to_create_reply
448+
HV00N E ERRCODE_FDW_UNABLE_TO_ESTABLISH_CONNECTION fdw_unable_to_establish_connection
442449

443450
Section: Class P0 - PL/pgSQL Error
444451

0 commit comments

Comments
 (0)