Hello This proposal is related to exception processing. Inside exception handler we can get some basic info about exception - message text and message code. There are other fields - but these fields are no available now in PL/pgSQL. The cheap access to fields inside ErrorData structure can be implemented inside GET DIAGNOSTICS statements - this statement is created for this purpose. I propose a new thee identifiers, that can be used there: ERROR_DETAIL, ERROR_HINT and ERROR_CONTEXT. Using is simple:
CREATE OR REPLACE FUNCTION foo() RETURNS void AS $$ DECLARE _detail text; _hint text; _context text; BEGIN RAISE EXCEPTION 'some message' USING DETAIL = 'some message specific description', HINT = 'some hint related to messgae'; EXCEPTION WHEN OTHERS THEN GET DIAGNOSTICS _detail = ERROR_DETAIL, _hint = ERROR_HINT, _context = ERROR_CONTEXT; RAISE WARNING 'caught message: %', SQLERRM USING DETAIL = e'\ncaught detail: ' || _detail || e'\ncaught hint: ' || _hint || e'\ncaught context: ' || _context; END; $$ LANGUAGE plpgsql; SELECT foo(); A implementation of ERROR_DETAIL and ERROR_HINT is simple and without possible performance issues. It has zero impact on performance. A implementation of ERROR_CONTEXT is not without impact on performance, because context should be collected when exception is caught. One solution is removing a ERROR_CONTEXT from proposal. Second solution can be a design of enhanced syntax for exception trap like (it means - collect CONTEXT when exception is handled) BEGIN EXCEPTION (ERROR_CONTEXT=true) WHEN OTHERS THEN ... END Getting a context can be a problem - but it is very important information, that can significantly help with exception's explanation. ideas, notes? Regards Pavel Stehule
*** ./src/pl/plpgsql/src/gram.y.orig 2011-05-18 19:41:56.755678378 +0200 --- ./src/pl/plpgsql/src/gram.y 2011-05-21 21:03:28.799168296 +0200 *************** *** 250,255 **** --- 250,256 ---- %token <keyword> K_CLOSE %token <keyword> K_COLLATE %token <keyword> K_CONSTANT + %token <keyword> K_CONTEXT %token <keyword> K_CONTINUE %token <keyword> K_CURSOR %token <keyword> K_DEBUG *************** *** 263,268 **** --- 264,272 ---- %token <keyword> K_END %token <keyword> K_ERRCODE %token <keyword> K_ERROR + %token <keyword> K_ERROR_CONTEXT + %token <keyword> K_ERROR_DETAIL + %token <keyword> K_ERROR_HINT %token <keyword> K_EXCEPTION %token <keyword> K_EXECUTE %token <keyword> K_EXIT *************** *** 877,882 **** --- 881,895 ---- else if (tok_is_keyword(tok, &yylval, K_RESULT_OID, "result_oid")) $$ = PLPGSQL_GETDIAG_RESULT_OID; + else if (tok_is_keyword(tok, &yylval, + K_ERROR_DETAIL, "error_detail")) + $$ = PLPGSQL_GETDIAG_ERROR_DETAIL; + else if (tok_is_keyword(tok, &yylval, + K_ERROR_HINT, "error_hint")) + $$ = PLPGSQL_GETDIAG_ERROR_HINT; + else if (tok_is_keyword(tok, &yylval, + K_ERROR_CONTEXT, "error_context")) + $$ = PLPGSQL_GETDIAG_ERROR_CONTEXT; else yyerror("unrecognized GET DIAGNOSTICS item"); } *************** *** 2141,2146 **** --- 2154,2162 ---- | K_DUMP | K_ERRCODE | K_ERROR + | K_ERROR_CONTEXT + | K_ERROR_DETAIL + | K_ERROR_HINT | K_FIRST | K_FORWARD | K_HINT *** ./src/pl/plpgsql/src/pl_exec.c.orig 2011-05-18 19:42:15.458152167 +0200 --- ./src/pl/plpgsql/src/pl_exec.c 2011-05-21 21:49:02.593299349 +0200 *************** *** 1081,1089 **** --- 1081,1097 ---- { ErrorData *edata; ListCell *e; + ErrorContextCallback *econtext; + estate->err_text = gettext_noop("during exception cleanup"); + /* Collect a context info */ + for (econtext = error_context_stack; + econtext != NULL; + econtext = econtext->previous) + (*econtext->callback) (econtext->arg); + /* Save error info */ MemoryContextSwitchTo(oldcontext); edata = CopyErrorData(); *************** *** 1449,1454 **** --- 1457,1504 ---- ObjectIdGetDatum(estate->eval_lastoid), OIDOID, &isnull); break; + case PLPGSQL_GETDIAG_ERROR_DETAIL: + case PLPGSQL_GETDIAG_ERROR_HINT: + case PLPGSQL_GETDIAG_ERROR_CONTEXT: + { + char *strval = NULL; + Datum value; + + /* + * Now a fields based on processing of Error Data + * are handled. + */ + if (estate->cur_error == NULL) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("access to exception's info outside exception handler"))); + switch (diag_item->kind) + { + case PLPGSQL_GETDIAG_ERROR_DETAIL: + strval = estate->cur_error->detail; + break; + case PLPGSQL_GETDIAG_ERROR_HINT: + strval = estate->cur_error->hint; + break; + case PLPGSQL_GETDIAG_ERROR_CONTEXT: + strval = estate->cur_error->context; + break; + } + + if (strval != NULL) + { + value = PointerGetDatum(cstring_to_text(strval)); + } + else + { + isnull = true; + value = (Datum) 0; + } + + exec_assign_value(estate, var, + value, TEXTOID, &isnull); + break; + } default: elog(ERROR, "unrecognized attribute request: %d", *** ./src/pl/plpgsql/src/pl_funcs.c.orig 2011-05-21 20:59:52.557887117 +0200 --- ./src/pl/plpgsql/src/pl_funcs.c 2011-05-21 21:04:45.510124756 +0200 *************** *** 1409,1414 **** --- 1409,1426 ---- printf("RESULT_OID"); break; + case PLPGSQL_GETDIAG_ERROR_CONTEXT: + printf("ERROR_CONTEXT"); + break; + + case PLPGSQL_GETDIAG_ERROR_DETAIL: + printf("ERROR_DETAIL"); + break; + + case PLPGSQL_GETDIAG_ERROR_HINT: + printf("ERROR_HINT"); + break; + default: printf("???"); break; *** ./src/pl/plpgsql/src/plpgsql.h.orig 2011-05-18 19:42:06.402954431 +0200 --- ./src/pl/plpgsql/src/plpgsql.h 2011-05-21 20:58:17.139277824 +0200 *************** *** 126,132 **** enum { PLPGSQL_GETDIAG_ROW_COUNT, ! PLPGSQL_GETDIAG_RESULT_OID }; /* -------- --- 126,135 ---- enum { PLPGSQL_GETDIAG_ROW_COUNT, ! PLPGSQL_GETDIAG_RESULT_OID, ! PLPGSQL_GETDIAG_ERROR_CONTEXT, ! PLPGSQL_GETDIAG_ERROR_DETAIL, ! PLPGSQL_GETDIAG_ERROR_HINT }; /* -------- *** ./src/pl/plpgsql/src/pl_scanner.c.orig 2011-05-18 14:22:29.000000000 +0200 --- ./src/pl/plpgsql/src/pl_scanner.c 2011-05-21 20:57:13.017519538 +0200 *************** *** 116,121 **** --- 116,124 ---- PG_KEYWORD("dump", K_DUMP, UNRESERVED_KEYWORD) PG_KEYWORD("errcode", K_ERRCODE, UNRESERVED_KEYWORD) PG_KEYWORD("error", K_ERROR, UNRESERVED_KEYWORD) + PG_KEYWORD("error_context", K_ERROR_CONTEXT, UNRESERVED_KEYWORD) + PG_KEYWORD("error_detail", K_ERROR_DETAIL, UNRESERVED_KEYWORD) + PG_KEYWORD("error_hint", K_ERROR_HINT, UNRESERVED_KEYWORD) PG_KEYWORD("first", K_FIRST, UNRESERVED_KEYWORD) PG_KEYWORD("forward", K_FORWARD, UNRESERVED_KEYWORD) PG_KEYWORD("hint", K_HINT, UNRESERVED_KEYWORD)
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers