*** a/doc/src/sgml/plpgsql.sgml
--- b/doc/src/sgml/plpgsql.sgml
***************
*** 2712,2717 **** END;
--- 2712,2765 ----
      </para>
     </sect3>
    </sect2>
+ 
+   <sect2 id="plpgsql-get-diagnostics-context">
+    <title>Obtaining information about an calls stack</title>
+ 
+    <para>
+ 
+ <synopsis>
+ GET <optional> CURRENT </optional> DIAGNOSTICS <replaceable>variable</replaceable> = <replaceable>PG_CONTEXT</replaceable> <optional> , ... </optional>;
+ </synopsis>
+ 
+ 
+     With command <command>GET DIAGNOSTICS</command> and status
+     item <varname>PG_CONTEXT</> is possible to get line(s) of
+     text describing the call stack. A first row is related to
+     current function and currently executed <command>GET DIAGNOSTICS</command>
+     command. Second row is related to first outer function,
+     and related statement, etc.
+ 
+ <programlisting>
+ CREATE OR REPLACE FUNCTION public.outer_func() RETURNS integer AS $$
+ BEGIN
+   RETURN inner_func();
+ END;
+ $$ LANGUAGE plpgsql;
+ 
+ CREATE OR REPLACE FUNCTION public.inner_func() RETURNS integer AS  $$
+ DECLARE
+   stack text;
+ BEGIN
+   GET DIAGNOSTICS stack = PG_CONTEXT;
+   RAISE NOTICE e'--- Call Stack ---\n%', stack;
+   RETURN 1;
+ END;
+ $$ LANGUAGE plpgsql;
+ 
+ SELECT outer_func();
+ 
+ NOTICE:  --- Call Stack ---
+ PL/pgSQL function inner_func() line 4 at GET DIAGNOSTICS
+ PL/pgSQL function outer_func() line 3 at RETURN
+  outer_func
+  ------------
+            1
+ (1 row)
+ </programlisting>
+ 
+    </para>
+   </sect2>
    </sect1>
  
    <sect1 id="plpgsql-cursors">
*** a/src/backend/utils/error/elog.c
--- b/src/backend/utils/error/elog.c
***************
*** 3120,3122 **** trace_recovery(int trace_level)
--- 3120,3168 ----
  
  	return trace_level;
  }
+ 
+ /*
+  * InvokeErrorCallbacks - invoke registrated error callback functions.
+  */
+ char *
+ InvokeErrorCallbacks(void)
+ {
+ 	ErrorData  *edata;
+ 	ErrorContextCallback *econtext;
+ 	MemoryContext oldcontext = CurrentMemoryContext;
+ 	char		*result;
+ 
+ 	/* this function should not be started in exception handler */
+ 	Assert(recursion_depth == 0);
+ 
+ 	if (++errordata_stack_depth >= ERRORDATA_STACK_SIZE)
+ 	{
+ 		errordata_stack_depth = -1;		/* make room on stack */
+ 		ereport(PANIC, (errmsg_internal("ERRORDATA_STACK_SIZE exceeded")));
+ 	}
+ 
+ 	/* Initialize data for this error frame */
+ 	edata = &errordata[errordata_stack_depth];
+ 	MemSet(edata, 0, sizeof(ErrorData));
+ 
+ 	/* Use ErrorContext as short living context */
+ 	MemoryContextSwitchTo(ErrorContext);
+ 
+ 	/*
+ 	 * Call any context callback functions.  Errors occurring in callback
+ 	 * functions will be treated as recursive errors --- this ensures we will
+ 	 * avoid infinite recursion (see errstart).
+ 	 */
+ 	for (econtext = error_context_stack;
+ 		 econtext != NULL;
+ 		 econtext = econtext->previous)
+ 		(*econtext->callback) (econtext->arg);
+ 
+ 	MemoryContextSwitchTo(oldcontext);
+ 	result = pstrdup(edata->context ? edata->context : "");
+ 
+ 	/* Reset error stack */
+ 	FlushErrorState();
+ 
+ 	return result;
+ }
*** a/src/include/utils/elog.h
--- b/src/include/utils/elog.h
***************
*** 406,411 **** extern void FlushErrorState(void);
--- 406,413 ----
  extern void ReThrowError(ErrorData *edata) __attribute__((noreturn));
  extern void pg_re_throw(void) __attribute__((noreturn));
  
+ extern char *InvokeErrorCallbacks(void);
+ 
  /* Hook for intercepting messages before they are sent to the server log */
  typedef void (*emit_log_hook_type) (ErrorData *edata);
  extern PGDLLIMPORT emit_log_hook_type emit_log_hook;
*** a/src/pl/plpgsql/src/pl_exec.c
--- b/src/pl/plpgsql/src/pl_exec.c
***************
*** 1574,1579 **** exec_stmt_getdiag(PLpgSQL_execstate *estate, PLpgSQL_stmt_getdiag *stmt)
--- 1574,1591 ----
  									 estate->cur_error->message);
  				break;
  
+ 			case PLPGSQL_GETDIAG_CONTEXT:
+ 				{
+ 					char *context;
+ 
+ 					context = InvokeErrorCallbacks();
+ 
+ 					exec_assign_c_string(estate, var,
+ 										context);
+ 					pfree(context);
+ 				}
+ 				break;
+ 
  			default:
  				elog(ERROR, "unrecognized diagnostic item kind: %d",
  					 diag_item->kind);
*** a/src/pl/plpgsql/src/pl_funcs.c
--- b/src/pl/plpgsql/src/pl_funcs.c
***************
*** 273,278 **** plpgsql_getdiag_kindname(int kind)
--- 273,280 ----
  {
  	switch (kind)
  	{
+ 		case PLPGSQL_GETDIAG_CONTEXT:
+ 			return "PG_CONTEXT";
  		case PLPGSQL_GETDIAG_ROW_COUNT:
  			return "ROW_COUNT";
  		case PLPGSQL_GETDIAG_RESULT_OID:
*** a/src/pl/plpgsql/src/pl_gram.y
--- b/src/pl/plpgsql/src/pl_gram.y
***************
*** 298,303 **** static	List			*read_raise_options(void);
--- 298,304 ----
  %token <keyword>	K_OPTION
  %token <keyword>	K_OR
  %token <keyword>	K_PERFORM
+ %token <keyword>	K_PG_CONTEXT
  %token <keyword>	K_PG_EXCEPTION_CONTEXT
  %token <keyword>	K_PG_EXCEPTION_DETAIL
  %token <keyword>	K_PG_EXCEPTION_HINT
***************
*** 884,889 **** stmt_getdiag	: K_GET getdiag_area_opt K_DIAGNOSTICS getdiag_list ';'
--- 885,891 ----
  								/* these fields are disallowed in stacked case */
  								case PLPGSQL_GETDIAG_ROW_COUNT:
  								case PLPGSQL_GETDIAG_RESULT_OID:
+ 								case PLPGSQL_GETDIAG_CONTEXT:
  									if (new->is_stacked)
  										ereport(ERROR,
  												(errcode(ERRCODE_SYNTAX_ERROR),
***************
*** 956,961 **** getdiag_item :
--- 958,966 ----
  						int	tok = yylex();
  
  						if (tok_is_keyword(tok, &yylval,
+ 										   K_PG_CONTEXT, "pg_context"))
+ 							$$ = PLPGSQL_GETDIAG_CONTEXT;
+ 						else if (tok_is_keyword(tok, &yylval,
  										   K_ROW_COUNT, "row_count"))
  							$$ = PLPGSQL_GETDIAG_ROW_COUNT;
  						else if (tok_is_keyword(tok, &yylval,
***************
*** 2252,2257 **** unreserved_keyword	:
--- 2257,2263 ----
  				| K_NO
  				| K_NOTICE
  				| K_OPTION
+ 				| K_PG_CONTEXT
  				| K_PG_EXCEPTION_CONTEXT
  				| K_PG_EXCEPTION_DETAIL
  				| K_PG_EXCEPTION_HINT
*** a/src/pl/plpgsql/src/pl_scanner.c
--- b/src/pl/plpgsql/src/pl_scanner.c
***************
*** 130,135 **** static const ScanKeyword unreserved_keywords[] = {
--- 130,136 ----
  	PG_KEYWORD("no", K_NO, UNRESERVED_KEYWORD)
  	PG_KEYWORD("notice", K_NOTICE, UNRESERVED_KEYWORD)
  	PG_KEYWORD("option", K_OPTION, UNRESERVED_KEYWORD)
+ 	PG_KEYWORD("pg_context", K_PG_CONTEXT, UNRESERVED_KEYWORD)
  	PG_KEYWORD("pg_exception_context", K_PG_EXCEPTION_CONTEXT, UNRESERVED_KEYWORD)
  	PG_KEYWORD("pg_exception_detail", K_PG_EXCEPTION_DETAIL, UNRESERVED_KEYWORD)
  	PG_KEYWORD("pg_exception_hint", K_PG_EXCEPTION_HINT, UNRESERVED_KEYWORD)
*** a/src/pl/plpgsql/src/plpgsql.h
--- b/src/pl/plpgsql/src/plpgsql.h
***************
*** 122,127 **** enum
--- 122,128 ----
   */
  enum
  {
+ 	PLPGSQL_GETDIAG_CONTEXT,
  	PLPGSQL_GETDIAG_ROW_COUNT,
  	PLPGSQL_GETDIAG_RESULT_OID,
  	PLPGSQL_GETDIAG_ERROR_CONTEXT,
*** a/src/test/regress/expected/plpgsql.out
--- b/src/test/regress/expected/plpgsql.out
***************
*** 4863,4865 **** ERROR:  value for domain orderedarray violates check constraint "sorted"
--- 4863,4913 ----
  CONTEXT:  PL/pgSQL function testoa(integer,integer,integer) line 5 at assignment
  drop function arrayassign1();
  drop function testoa(x1 int, x2 int, x3 int);
+ -- access to call stack
+ create function inner_func(int)
+ returns int as $$
+ declare _context text;
+ begin
+   get diagnostics _context = pg_context;
+   raise notice '***%***', _context;
+   return 2 * $1;
+ end;
+ $$ language plpgsql;
+ create or replace function outer_func(int)
+ returns int as $$
+ begin
+   return inner_func($1);
+ end;
+ $$ language plpgsql;
+ create or replace function outer_outer_func(int)
+ returns int as $$
+ begin
+   return outer_func($1);
+ end;
+ $$ language plpgsql;
+ select outer_outer_func(10);
+ NOTICE:  ***PL/pgSQL function inner_func(integer) line 4 at GET DIAGNOSTICS
+ PL/pgSQL function outer_func(integer) line 3 at RETURN
+ PL/pgSQL function outer_outer_func(integer) line 3 at RETURN***
+ CONTEXT:  PL/pgSQL function outer_func(integer) line 3 at RETURN
+ PL/pgSQL function outer_outer_func(integer) line 3 at RETURN
+  outer_outer_func 
+ ------------------
+                20
+ (1 row)
+ 
+ -- repeated call should to work
+ select outer_outer_func(20);
+ NOTICE:  ***PL/pgSQL function inner_func(integer) line 4 at GET DIAGNOSTICS
+ PL/pgSQL function outer_func(integer) line 3 at RETURN
+ PL/pgSQL function outer_outer_func(integer) line 3 at RETURN***
+ CONTEXT:  PL/pgSQL function outer_func(integer) line 3 at RETURN
+ PL/pgSQL function outer_outer_func(integer) line 3 at RETURN
+  outer_outer_func 
+ ------------------
+                40
+ (1 row)
+ 
+ drop function outer_outer_func(int);
+ drop function outer_func(int);
+ drop function inner_func(int);
*** a/src/test/regress/sql/plpgsql.sql
--- b/src/test/regress/sql/plpgsql.sql
***************
*** 3848,3850 **** select testoa(1,2,1); -- fail at update
--- 3848,3883 ----
  
  drop function arrayassign1();
  drop function testoa(x1 int, x2 int, x3 int);
+ 
+ -- access to call stack
+ create function inner_func(int)
+ returns int as $$
+ declare _context text;
+ begin
+   get diagnostics _context = pg_context;
+   raise notice '***%***', _context;
+   return 2 * $1;
+ end;
+ $$ language plpgsql;
+ 
+ create or replace function outer_func(int)
+ returns int as $$
+ begin
+   return inner_func($1);
+ end;
+ $$ language plpgsql;
+ 
+ create or replace function outer_outer_func(int)
+ returns int as $$
+ begin
+   return outer_func($1);
+ end;
+ $$ language plpgsql;
+ 
+ select outer_outer_func(10);
+ -- repeated call should to work
+ select outer_outer_func(20);
+ 
+ drop function outer_outer_func(int);
+ drop function outer_func(int);
+ drop function inner_func(int);
