Hello 2011/7/14 Alvaro Herrera <alvhe...@commandprompt.com>: > Excerpts from Pavel Stehule's message of jue jul 14 16:25:56 -0400 2011: >> 2011/7/14 Alvaro Herrera <alvhe...@commandprompt.com>: >> > A couple items for this patch: > >> it is good idea > > Thanks ... I expect you're going to resubmit the patch based on David's > last version and my comments? >
yes, see a attachment Regards Pavel > -- > Álvaro Herrera <alvhe...@commandprompt.com> > The PostgreSQL Company - Command Prompt, Inc. > PostgreSQL Replication, Consulting, Custom Development, 24x7 support >
*** ./doc/src/sgml/plpgsql.sgml.orig 2011-07-15 07:53:03.069787671 +0200 --- ./doc/src/sgml/plpgsql.sgml 2011-07-15 08:36:00.504591377 +0200 *************** *** 1387,1393 **** command, which has the form: <synopsis> ! GET DIAGNOSTICS <replaceable>variable</replaceable> = <replaceable>item</replaceable> <optional> , ... </optional>; </synopsis> This command allows retrieval of system status indicators. Each --- 1387,1393 ---- command, which has the form: <synopsis> ! GET <optional> CURRENT </optional> DIAGNOSTICS <replaceable>variable</replaceable> = <replaceable>item</replaceable> <optional> , ... </optional>; </synopsis> This command allows retrieval of system status indicators. Each *************** *** 1488,1493 **** --- 1488,1580 ---- </sect2> + <sect2 id="plpgsql-exception-diagnostics"> + <title>Obtaining the Exception Status</title> + + <para> + Inside an exception handler, one may retrieve detailed + information about the current exception using THE + <command>GET STACKED DIAGNOSTICS</command> command, which has the form: + + <synopsis> + GET STACKED DIAGNOSTICS <replaceable>variable</replaceable> = <replaceable>item</replaceable> <optional> , ... </optional>; + </synopsis> + </para> + + <para> + This command allows retrieval of the exception's data. Each + <replaceable>item</replaceable> is a key word identifying a state + value to be assigned to the specified variable (which should be + of the right data type to receive it). The currently available + status items are: + + <table id="plpgsql-exception-diagnostics-values"> + <title>Stacked diagnostics values</title> + <tgroup cols="3"> + <thead> + <row> + <entry>Name</entry> + <entry>Return type</entry> + <entry>Description</entry> + </row> + </thead> + <tbody> + <row> + <entry>RETURNED_SQLSTATE</entry> + <entry>text</entry> + <entry>the SQLSTATE of the exception</entry> + </row> + <row> + <entry>MESSAGE_TEXT</entry> + <entry>text</entry> + <entry>the text of the exception's message</entry> + </row> + <row> + <entry>PG_EXCEPTION_DETAIL</entry> + <entry>text</entry> + <entry>the text of the exception's detail message</entry> + </row> + <row> + <entry>PG_EXCEPTION_HINT</entry> + <entry>text</entry> + <entry>the text of the exception's hint message</entry> + </row> + <row> + <entry>PG_EXCEPTION_CONTEXT</entry> + <entry>text</entry> + <entry>lines of text describing the call stack</entry> + </row> + </tbody> + </tgroup> + </table> + </para> + + <para> + If an exception does not contain a value for an item, an empty string + will be returned. + </para> + + <para> + An example: + <programlisting> + DECLARE + text_var1 text; + text_var2 text; + text_var3 text; + BEGIN + -- some processing which might cause an exception + ... + EXCEPTION WHEN OTHERS THEN + GET STACKED DIAGNOSTICS text_var1 = MESSAGE_TEXT, + text_var2 = PG_EXCEPTION_DETAIL, + text_var3 = PG_EXCEPTION_HINT; + END; + </programlisting> + </para> + + + </sect2> + <sect2 id="plpgsql-statements-null"> <title>Doing Nothing At All</title> *** ./src/backend/utils/errcodes.txt.orig 2011-07-15 07:53:03.070787661 +0200 --- ./src/backend/utils/errcodes.txt 2011-07-15 08:01:04.522609180 +0200 *************** *** 132,137 **** --- 132,140 ---- 0P000 E ERRCODE_INVALID_ROLE_SPECIFICATION invalid_role_specification + Section: Class 0Z - Diagnostics Exception + 0Z002 E ERRCODE_STACKED_DIAGNOSTICS_ACCESSED_WITHOUT_ACTIVE_HANDLER stacked_diagnostics_accessed_without_active_handler + Section: Class 20 - Case Not Found 20000 E ERRCODE_CASE_NOT_FOUND case_not_found *** ./src/pl/plpgsql/src/gram.y.orig 2011-07-15 07:53:03.071787651 +0200 --- ./src/pl/plpgsql/src/gram.y 2011-07-15 09:29:27.959407772 +0200 *************** *** 206,211 **** --- 206,212 ---- %type <list> getdiag_list %type <diagitem> getdiag_list_item %type <ival> getdiag_item getdiag_target + %type <boolean> getdiag_opt %type <ival> opt_scrollable %type <fetch> opt_fetch_direction *************** *** 250,256 **** --- 251,259 ---- %token <keyword> K_CLOSE %token <keyword> K_COLLATE %token <keyword> K_CONSTANT + %token <keyword> K_CONTEXT %token <keyword> K_CONTINUE + %token <keyword> K_CURRENT %token <keyword> K_CURSOR %token <keyword> K_DEBUG %token <keyword> K_DECLARE *************** *** 263,268 **** --- 266,274 ---- %token <keyword> K_END %token <keyword> K_ERRCODE %token <keyword> K_ERROR + %token <keyword> K_EXCEPTION_CONTEXT + %token <keyword> K_EXCEPTION_DETAIL + %token <keyword> K_EXCEPTION_HINT %token <keyword> K_EXCEPTION %token <keyword> K_EXECUTE %token <keyword> K_EXIT *************** *** 284,289 **** --- 290,296 ---- %token <keyword> K_LOG %token <keyword> K_LOOP %token <keyword> K_MESSAGE + %token <keyword> K_MESSAGE_TEXT %token <keyword> K_MOVE %token <keyword> K_NEXT %token <keyword> K_NO *************** *** 300,311 **** --- 307,320 ---- %token <keyword> K_RELATIVE %token <keyword> K_RESULT_OID %token <keyword> K_RETURN + %token <keyword> K_RETURNED_SQLSTATE %token <keyword> K_REVERSE %token <keyword> K_ROWTYPE %token <keyword> K_ROW_COUNT %token <keyword> K_SCROLL %token <keyword> K_SLICE %token <keyword> K_SQLSTATE + %token <keyword> K_STACKED %token <keyword> K_STRICT %token <keyword> K_THEN %token <keyword> K_TO *************** *** 832,845 **** } ; ! stmt_getdiag : K_GET K_DIAGNOSTICS getdiag_list ';' { PLpgSQL_stmt_getdiag *new; new = palloc0(sizeof(PLpgSQL_stmt_getdiag)); new->cmd_type = PLPGSQL_STMT_GETDIAG; new->lineno = plpgsql_location_to_lineno(@1); ! new->diag_items = $3; $$ = (PLpgSQL_stmt *)new; } --- 841,898 ---- } ; ! stmt_getdiag : K_GET getdiag_opt K_DIAGNOSTICS getdiag_list ';' { PLpgSQL_stmt_getdiag *new; + ListCell *lc; new = palloc0(sizeof(PLpgSQL_stmt_getdiag)); new->cmd_type = PLPGSQL_STMT_GETDIAG; new->lineno = plpgsql_location_to_lineno(@1); ! new->is_stacked = $2; ! new->diag_items = $4; ! ! /* ! * stacked diagnostics statements allows only access ! * to exception data fields. whereas current diagnostics ! * statement disallow access to exception data fields. ! */ ! foreach(lc, new->diag_items) ! { ! PLpgSQL_diag_item *ditem = (PLpgSQL_diag_item *) lfirst(lc); ! ! if (new->is_stacked) ! { ! switch (ditem->kind) ! { ! /* these fields are disallowed in stacked diagnostics statement */ ! case PLPGSQL_GETDIAG_ROW_COUNT: ! case PLPGSQL_GETDIAG_RESULT_OID: ! ereport(ERROR, ! (errcode(ERRCODE_SYNTAX_ERROR), ! errmsg("diagnostics value \"%s\" is not allowed in current diagnostics statement", ! plpgsql_getdiag_kindname(ditem->kind)), ! parser_errposition(@1))); ! } ! } ! else ! { ! switch (ditem->kind) ! { ! /* these fields are disallowed in current diagnostics statement */ ! case PLPGSQL_GETDIAG_ERROR_CONTEXT: ! case PLPGSQL_GETDIAG_ERROR_DETAIL: ! case PLPGSQL_GETDIAG_ERROR_HINT: ! case PLPGSQL_GETDIAG_RETURNED_SQLSTATE: ! case PLPGSQL_GETDIAG_MESSAGE_TEXT: ! ereport(ERROR, ! (errcode(ERRCODE_SYNTAX_ERROR), ! errmsg("diagnostics value \"%s\" is not allowed in stacked diagnostics statement", ! plpgsql_getdiag_kindname(ditem->kind)), ! parser_errposition(@1))); ! } ! } ! } $$ = (PLpgSQL_stmt *)new; } *************** *** 867,872 **** --- 920,939 ---- } ; + getdiag_opt : + { + $$ = false; + } + | K_CURRENT + { + $$ = false; + } + | K_STACKED + { + $$ = true; + } + ; + getdiag_item : { int tok = yylex(); *************** *** 877,882 **** --- 944,964 ---- else if (tok_is_keyword(tok, &yylval, K_RESULT_OID, "result_oid")) $$ = PLPGSQL_GETDIAG_RESULT_OID; + else if (tok_is_keyword(tok, &yylval, + K_EXCEPTION_DETAIL, "pg_exception_detail")) + $$ = PLPGSQL_GETDIAG_ERROR_DETAIL; + else if (tok_is_keyword(tok, &yylval, + K_EXCEPTION_HINT, "pg_exception_hint")) + $$ = PLPGSQL_GETDIAG_ERROR_HINT; + else if (tok_is_keyword(tok, &yylval, + K_EXCEPTION_CONTEXT, "pg_exception_context")) + $$ = PLPGSQL_GETDIAG_ERROR_CONTEXT; + else if (tok_is_keyword(tok, &yylval, + K_MESSAGE_TEXT, "message_text")) + $$ = PLPGSQL_GETDIAG_MESSAGE_TEXT; + else if (tok_is_keyword(tok, &yylval, + K_RETURNED_SQLSTATE, "returned_sqlstate")) + $$ = PLPGSQL_GETDIAG_RETURNED_SQLSTATE; else yyerror("unrecognized GET DIAGNOSTICS item"); } *************** *** 2135,2146 **** --- 2217,2232 ---- | K_ARRAY | K_BACKWARD | K_CONSTANT + | K_CURRENT | K_CURSOR | K_DEBUG | K_DETAIL | K_DUMP | K_ERRCODE | K_ERROR + | K_EXCEPTION_CONTEXT + | K_EXCEPTION_DETAIL + | K_EXCEPTION_HINT | K_FIRST | K_FORWARD | K_HINT *************** *** 2149,2154 **** --- 2235,2241 ---- | K_LAST | K_LOG | K_MESSAGE + | K_MESSAGE_TEXT | K_NEXT | K_NO | K_NOTICE *************** *** 2157,2168 **** --- 2244,2257 ---- | K_QUERY | K_RELATIVE | K_RESULT_OID + | K_RETURNED_SQLSTATE | K_REVERSE | K_ROW_COUNT | K_ROWTYPE | K_SCROLL | K_SLICE | K_SQLSTATE + | K_STACKED | K_TYPE | K_USE_COLUMN | K_USE_VARIABLE *** ./src/pl/plpgsql/src/pl_exec.c.orig 2011-07-15 07:53:03.073787632 +0200 --- ./src/pl/plpgsql/src/pl_exec.c 2011-07-15 09:17:14.293046424 +0200 *************** *** 1411,1416 **** --- 1411,1436 ---- return PLPGSQL_RC_OK; } + + /* ---------- + * Small routine that ensure a transformation char *str to text datum. + * Use a empty string, when str pointer is NULL. + * ---------- + */ + static void + exec_assign_dg_text(PLpgSQL_execstate *estate, PLpgSQL_datum *var, const char *cstr) + { + bool isnull = false; + Datum value; + + if (cstr != NULL) + value = PointerGetDatum(cstring_to_text(cstr)); + else + value = PointerGetDatum(cstring_to_text("")); + + exec_assign_value(estate, var, value, TEXTOID, &isnull); + } + /* ---------- * exec_stmt_getdiag Put internal PG information into * specified variables. *************** *** 1435,1440 **** --- 1455,1469 ---- if (var == NULL) continue; + /* + * Stacked diagnostics statement is based on processing of Error Data. + * These data should be available. + */ + if (stmt->is_stacked && estate->cur_error == NULL) + ereport(ERROR, + (errcode(ERRCODE_STACKED_DIAGNOSTICS_ACCESSED_WITHOUT_ACTIVE_HANDLER), + errmsg("stacked diagnostics accessed without active handler"))); + switch (diag_item->kind) { case PLPGSQL_GETDIAG_ROW_COUNT: *************** *** 1445,1456 **** break; case PLPGSQL_GETDIAG_RESULT_OID: - exec_assign_value(estate, var, ObjectIdGetDatum(estate->eval_lastoid), OIDOID, &isnull); break; default: elog(ERROR, "unrecognized attribute request: %d", diag_item->kind); --- 1474,1509 ---- break; case PLPGSQL_GETDIAG_RESULT_OID: exec_assign_value(estate, var, ObjectIdGetDatum(estate->eval_lastoid), OIDOID, &isnull); break; + case PLPGSQL_GETDIAG_ERROR_DETAIL: + exec_assign_dg_text(estate, var, + estate->cur_error->detail); + break; + + case PLPGSQL_GETDIAG_ERROR_HINT: + exec_assign_dg_text(estate, var, + estate->cur_error->hint); + break; + + case PLPGSQL_GETDIAG_ERROR_CONTEXT: + exec_assign_dg_text(estate, var, + estate->cur_error->context); + break; + + case PLPGSQL_GETDIAG_RETURNED_SQLSTATE: + exec_assign_dg_text(estate, var, + unpack_sql_state(estate->cur_error->sqlerrcode)); + break; + + case PLPGSQL_GETDIAG_MESSAGE_TEXT: + exec_assign_dg_text(estate, var, + estate->cur_error->message); + break; + default: elog(ERROR, "unrecognized attribute request: %d", diag_item->kind); *** ./src/pl/plpgsql/src/pl_funcs.c.orig 2011-07-15 07:53:03.074787623 +0200 --- ./src/pl/plpgsql/src/pl_funcs.c 2011-07-15 08:49:08.397831023 +0200 *************** *** 265,270 **** --- 265,296 ---- return "unknown"; } + /* + * Returns a name of diagnostic value for GET DIAGNOSTICS statement + */ + const char * + plpgsql_getdiag_kindname(int kind) + { + switch (kind) + { + case PLPGSQL_GETDIAG_ROW_COUNT: + return "ROW_COUNT"; + case PLPGSQL_GETDIAG_RESULT_OID: + return "RESULT_OID"; + case PLPGSQL_GETDIAG_ERROR_CONTEXT: + return "PG_EXCEPTION_CONTEXT"; + case PLPGSQL_GETDIAG_ERROR_DETAIL: + return "PG_EXCEPTION_DETAIL"; + case PLPGSQL_GETDIAG_ERROR_HINT: + return "PG_EXCEPTION_HINT"; + case PLPGSQL_GETDIAG_RETURNED_SQLSTATE: + return "RETURNED_SQLSTATE"; + case PLPGSQL_GETDIAG_MESSAGE_TEXT: + return "MESSAGE_TEXT"; + } + + return "unknown"; + }; /********************************************************************** * Release memory when a PL/pgSQL function is no longer needed *************** *** 1389,1395 **** ListCell *lc; dump_ind(); ! printf("GET DIAGNOSTICS "); foreach(lc, stmt->diag_items) { PLpgSQL_diag_item *diag_item = (PLpgSQL_diag_item *) lfirst(lc); --- 1415,1421 ---- ListCell *lc; dump_ind(); ! printf("GET %s DIAGNOSTICS ", stmt->is_stacked ? "STACKED" : "CURRENT"); foreach(lc, stmt->diag_items) { PLpgSQL_diag_item *diag_item = (PLpgSQL_diag_item *) lfirst(lc); *************** *** 1397,1418 **** if (lc != list_head(stmt->diag_items)) printf(", "); ! printf("{var %d} = ", diag_item->target); ! ! switch (diag_item->kind) ! { ! case PLPGSQL_GETDIAG_ROW_COUNT: ! printf("ROW_COUNT"); ! break; ! ! case PLPGSQL_GETDIAG_RESULT_OID: ! printf("RESULT_OID"); ! break; ! ! default: ! printf("???"); ! break; ! } } printf("\n"); } --- 1423,1430 ---- if (lc != list_head(stmt->diag_items)) printf(", "); ! printf("{var %d} = %s", diag_item->target, ! plpgsql_getdiag_kindname(diag_item->kind)); } printf("\n"); } *** ./src/pl/plpgsql/src/plpgsql.h.orig 2011-07-15 07:53:03.077787597 +0200 --- ./src/pl/plpgsql/src/plpgsql.h 2011-07-15 08:48:01.908423020 +0200 *************** *** 126,132 **** enum { PLPGSQL_GETDIAG_ROW_COUNT, ! PLPGSQL_GETDIAG_RESULT_OID }; /* -------- --- 126,137 ---- enum { PLPGSQL_GETDIAG_ROW_COUNT, ! PLPGSQL_GETDIAG_RESULT_OID, ! PLPGSQL_GETDIAG_ERROR_CONTEXT, ! PLPGSQL_GETDIAG_ERROR_DETAIL, ! PLPGSQL_GETDIAG_ERROR_HINT, ! PLPGSQL_GETDIAG_RETURNED_SQLSTATE, ! PLPGSQL_GETDIAG_MESSAGE_TEXT }; /* -------- *************** *** 377,382 **** --- 382,388 ---- int cmd_type; int lineno; List *diag_items; /* List of PLpgSQL_diag_item */ + bool is_stacked; /* true when it access a second area of diagnostics info */ } PLpgSQL_stmt_getdiag; *************** *** 929,934 **** --- 935,941 ---- * ---------- */ extern const char *plpgsql_stmt_typename(PLpgSQL_stmt *stmt); + extern const char *plpgsql_getdiag_kindname(int kind); extern void plpgsql_free_function_memory(PLpgSQL_function *func); extern void plpgsql_dumptree(PLpgSQL_function *func); *** ./src/pl/plpgsql/src/pl_scanner.c.orig 2011-07-15 07:53:03.075787614 +0200 --- ./src/pl/plpgsql/src/pl_scanner.c 2011-07-15 08:01:04.531609103 +0200 *************** *** 110,115 **** --- 110,116 ---- PG_KEYWORD("array", K_ARRAY, UNRESERVED_KEYWORD) PG_KEYWORD("backward", K_BACKWARD, UNRESERVED_KEYWORD) PG_KEYWORD("constant", K_CONSTANT, UNRESERVED_KEYWORD) + PG_KEYWORD("current", K_CURRENT, UNRESERVED_KEYWORD) PG_KEYWORD("cursor", K_CURSOR, UNRESERVED_KEYWORD) PG_KEYWORD("debug", K_DEBUG, UNRESERVED_KEYWORD) PG_KEYWORD("detail", K_DETAIL, UNRESERVED_KEYWORD) *************** *** 124,143 **** --- 125,150 ---- PG_KEYWORD("last", K_LAST, UNRESERVED_KEYWORD) PG_KEYWORD("log", K_LOG, UNRESERVED_KEYWORD) PG_KEYWORD("message", K_MESSAGE, UNRESERVED_KEYWORD) + PG_KEYWORD("message_text", K_MESSAGE_TEXT, UNRESERVED_KEYWORD) PG_KEYWORD("next", K_NEXT, UNRESERVED_KEYWORD) PG_KEYWORD("no", K_NO, UNRESERVED_KEYWORD) PG_KEYWORD("notice", K_NOTICE, UNRESERVED_KEYWORD) PG_KEYWORD("option", K_OPTION, UNRESERVED_KEYWORD) + PG_KEYWORD("pg_exception_context", K_EXCEPTION_CONTEXT, UNRESERVED_KEYWORD) + PG_KEYWORD("pg_exception_detail", K_EXCEPTION_DETAIL, UNRESERVED_KEYWORD) + PG_KEYWORD("pg_exception_hint", K_EXCEPTION_HINT, UNRESERVED_KEYWORD) PG_KEYWORD("prior", K_PRIOR, UNRESERVED_KEYWORD) PG_KEYWORD("query", K_QUERY, UNRESERVED_KEYWORD) PG_KEYWORD("relative", K_RELATIVE, UNRESERVED_KEYWORD) PG_KEYWORD("result_oid", K_RESULT_OID, UNRESERVED_KEYWORD) + PG_KEYWORD("returned_sqlstate", K_RETURNED_SQLSTATE, UNRESERVED_KEYWORD) PG_KEYWORD("reverse", K_REVERSE, UNRESERVED_KEYWORD) PG_KEYWORD("row_count", K_ROW_COUNT, UNRESERVED_KEYWORD) PG_KEYWORD("rowtype", K_ROWTYPE, UNRESERVED_KEYWORD) PG_KEYWORD("scroll", K_SCROLL, UNRESERVED_KEYWORD) PG_KEYWORD("slice", K_SLICE, UNRESERVED_KEYWORD) PG_KEYWORD("sqlstate", K_SQLSTATE, UNRESERVED_KEYWORD) + PG_KEYWORD("stacked", K_STACKED, UNRESERVED_KEYWORD) PG_KEYWORD("type", K_TYPE, UNRESERVED_KEYWORD) PG_KEYWORD("use_column", K_USE_COLUMN, UNRESERVED_KEYWORD) PG_KEYWORD("use_variable", K_USE_VARIABLE, UNRESERVED_KEYWORD) *** ./src/test/regress/expected/plpgsql.out.orig 2011-07-15 07:53:03.078787589 +0200 --- ./src/test/regress/expected/plpgsql.out 2011-07-15 08:01:04.534609076 +0200 *************** *** 4434,4436 **** --- 4434,4511 ---- drop function foreach_test(anyarray); drop type xy_tuple; + -- access to exception data + create or replace function bad_function() + returns int as $$ + declare v int := 0; + begin + return 10 / v; + end; + $$ language plpgsql; + create or replace function raise_function() + returns void as $$ + begin + raise exception 'custom exception' + using detail = 'some detail of custom exception', + hint = 'some hint related to custom exception'; + end; + $$ language plpgsql; + create or replace function stacked_diagnostics_test01() + returns void as $$ + declare _sqlstate text; _message text; _context text; + begin + perform bad_function(); + exception when others then + get stacked diagnostics + _sqlstate = returned_sqlstate, + _message = message_text, + _context = pg_exception_context; + raise notice 'sqlstate: %, message: %, context: [%]', _sqlstate, _message, replace(_context, e'\n', ' <- '); + end; + $$ language plpgsql; + select stacked_diagnostics_test01(); + NOTICE: sqlstate: 22012, message: division by zero, context: [PL/pgSQL function "bad_function" line 4 at RETURN <- SQL statement "SELECT bad_function()" <- PL/pgSQL function "stacked_diagnostics_test01" line 4 at PERFORM] + stacked_diagnostics_test01 + ---------------------------- + + (1 row) + + create or replace function stacked_diagnostics_test02() + returns void as $$ + declare _detail text; _hint text; _message text; + begin + perform raise_function(); + exception when others then + get stacked diagnostics + _message = message_text, + _detail = pg_exception_detail, + _hint = pg_exception_hint; + raise notice 'message: %, detail: %, hint: %', _message, _detail, _hint; + end; + $$ language plpgsql; + select stacked_diagnostics_test02(); + NOTICE: message: custom exception, detail: some detail of custom exception, hint: some hint related to custom exception + stacked_diagnostics_test02 + ---------------------------- + + (1 row) + + -- should to fail, cannot use stacked diagnostics statement outside handler + create or replace function stacked_diagnostics_test02() + returns void as $$ + declare _detail text; _hint text; _message text; + begin + get stacked diagnostics + _message = message_text, + _detail = pg_exception_detail, + _hint = pg_exception_hint; + raise notice 'message: %, detail: %, hint: %', _message, _detail, _hint; + end; + $$ language plpgsql; + select stacked_diagnostics_test02(); + ERROR: stacked diagnostics accessed without active handler + CONTEXT: PL/pgSQL function "stacked_diagnostics_test02" line 4 at GET DIAGNOSTICS + drop function bad_function(); + drop function raise_function(); + drop function stacked_diagnostics_test01(); + drop function stacked_diagnostics_test02(); *** ./src/test/regress/sql/plpgsql.sql.orig 2011-07-15 07:53:03.080787571 +0200 --- ./src/test/regress/sql/plpgsql.sql 2011-07-15 08:01:04.536609058 +0200 *************** *** 3489,3491 **** --- 3489,3563 ---- drop function foreach_test(anyarray); drop type xy_tuple; + + + -- access to exception data + create or replace function bad_function() + returns int as $$ + declare v int := 0; + begin + return 10 / v; + end; + $$ language plpgsql; + + create or replace function raise_function() + returns void as $$ + begin + raise exception 'custom exception' + using detail = 'some detail of custom exception', + hint = 'some hint related to custom exception'; + end; + $$ language plpgsql; + + create or replace function stacked_diagnostics_test01() + returns void as $$ + declare _sqlstate text; _message text; _context text; + begin + perform bad_function(); + exception when others then + get stacked diagnostics + _sqlstate = returned_sqlstate, + _message = message_text, + _context = pg_exception_context; + raise notice 'sqlstate: %, message: %, context: [%]', _sqlstate, _message, replace(_context, e'\n', ' <- '); + end; + $$ language plpgsql; + + select stacked_diagnostics_test01(); + + create or replace function stacked_diagnostics_test02() + returns void as $$ + declare _detail text; _hint text; _message text; + begin + perform raise_function(); + exception when others then + get stacked diagnostics + _message = message_text, + _detail = pg_exception_detail, + _hint = pg_exception_hint; + raise notice 'message: %, detail: %, hint: %', _message, _detail, _hint; + end; + $$ language plpgsql; + + select stacked_diagnostics_test02(); + + -- should to fail, cannot use stacked diagnostics statement outside handler + + create or replace function stacked_diagnostics_test02() + returns void as $$ + declare _detail text; _hint text; _message text; + begin + get stacked diagnostics + _message = message_text, + _detail = pg_exception_detail, + _hint = pg_exception_hint; + raise notice 'message: %, detail: %, hint: %', _message, _detail, _hint; + end; + $$ language plpgsql; + + select stacked_diagnostics_test02(); + + drop function bad_function(); + drop function raise_function(); + drop function stacked_diagnostics_test01(); + drop function stacked_diagnostics_test02();
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers