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

Reply via email to