diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 7f03f41..feb9984 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -3120,3 +3120,53 @@ trace_recovery(int trace_level)
 
 	return trace_level;
 }
+
+/*
+ * InvokeErrorCallbacks - invoke registrated error callback functions.
+ */
+char *
+InvokeErrorCallbacks(void)
+{
+	ErrorData  *edata;
+	ErrorContextCallback *econtext;
+	MemoryContext oldcontext = CurrentMemoryContext;
+	StringInfoData sinfo;
+
+	/* 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);
+
+	initStringInfo(&sinfo);
+
+	appendStringInfoString(&sinfo, "----- Call Stack -----\n");
+	if (edata->context)
+		appendStringInfoString(&sinfo, edata->context);
+
+	FlushErrorState();
+
+	return sinfo.data;
+}
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index 85bd2fd..fca826d 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -406,6 +406,8 @@ extern void FlushErrorState(void);
 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;
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 70e67d9..139c5e7 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -1574,6 +1574,18 @@ exec_stmt_getdiag(PLpgSQL_execstate *estate, PLpgSQL_stmt_getdiag *stmt)
 									 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);
diff --git a/src/pl/plpgsql/src/pl_funcs.c b/src/pl/plpgsql/src/pl_funcs.c
index 9d561c2..36f144a 100644
--- a/src/pl/plpgsql/src/pl_funcs.c
+++ b/src/pl/plpgsql/src/pl_funcs.c
@@ -273,6 +273,8 @@ plpgsql_getdiag_kindname(int kind)
 {
 	switch (kind)
 	{
+		case PLPGSQL_GETDIAG_CONTEXT:
+			return "PG_CONTEXT";
 		case PLPGSQL_GETDIAG_ROW_COUNT:
 			return "ROW_COUNT";
 		case PLPGSQL_GETDIAG_RESULT_OID:
diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y
index a790ee3..0ee9e2f 100644
--- a/src/pl/plpgsql/src/pl_gram.y
+++ b/src/pl/plpgsql/src/pl_gram.y
@@ -298,6 +298,7 @@ static	List			*read_raise_options(void);
 %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,6 +885,7 @@ stmt_getdiag	: K_GET getdiag_area_opt K_DIAGNOSTICS getdiag_list ';'
 								/* 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,6 +958,9 @@ getdiag_item :
 						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,6 +2257,7 @@ unreserved_keyword	:
 				| K_NO
 				| K_NOTICE
 				| K_OPTION
+				| K_PG_CONTEXT
 				| K_PG_EXCEPTION_CONTEXT
 				| K_PG_EXCEPTION_DETAIL
 				| K_PG_EXCEPTION_HINT
diff --git a/src/pl/plpgsql/src/pl_scanner.c b/src/pl/plpgsql/src/pl_scanner.c
index 9b6f57e..19aca1d 100644
--- a/src/pl/plpgsql/src/pl_scanner.c
+++ b/src/pl/plpgsql/src/pl_scanner.c
@@ -130,6 +130,7 @@ static const ScanKeyword unreserved_keywords[] = {
 	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)
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index 5cc44a0..6d45237 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -122,6 +122,7 @@ enum
  */
 enum
 {
+	PLPGSQL_GETDIAG_CONTEXT,
 	PLPGSQL_GETDIAG_ROW_COUNT,
 	PLPGSQL_GETDIAG_RESULT_OID,
 	PLPGSQL_GETDIAG_ERROR_CONTEXT,
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
index fdd8c6b..98e8cb8 100644
--- a/src/test/regress/expected/plpgsql.out
+++ b/src/test/regress/expected/plpgsql.out
@@ -4863,3 +4863,51 @@ ERROR:  value for domain orderedarray violates check constraint "sorted"
 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);
diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql
index 017bd0b..643c0fc 100644
--- a/src/test/regress/sql/plpgsql.sql
+++ b/src/test/regress/sql/plpgsql.sql
@@ -3848,3 +3848,36 @@ select testoa(1,2,1); -- fail at update
 
 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);
