eelog-plpgsql-2012-05-09.diff

application/octet-stream

Filename: eelog-plpgsql-2012-05-09.diff
Type: application/octet-stream
Part: 1
Message: enhanced error fields

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: unified
Series: patch 2012
File+
doc/src/sgml/plpgsql.sgml 59 2
src/pl/plpgsql/src/gram.y 81 0
src/pl/plpgsql/src/pl_exec.c 154 1
src/pl/plpgsql/src/pl_funcs.c 45 0
src/pl/plpgsql/src/plpgsql.h 20 2
src/pl/plpgsql/src/pl_scanner.c 9 0
src/test/regress/expected/plpgsql.out 59 0
src/test/regress/sql/plpgsql.sql 54 0
diff --git a/doc/src/sgml/plpgsql.sgml b/doc/src/sgml/plpgsql.sgml
index c5e9c2e..2316d3f 100644
--- a/doc/src/sgml/plpgsql.sgml
+++ b/doc/src/sgml/plpgsql.sgml
@@ -2639,6 +2639,51 @@ GET STACKED DIAGNOSTICS <replaceable>variable</replaceable> = <replaceable>item<
          <entry>text</entry>
          <entry>line(s) of text describing the call stack</entry>
         </row>
+        <row>
+         <entry><literal>COLUMN_NAME</literal></entry>
+         <entry>text</entry>
+         <entry>the name of column related to error, if any</entry>
+        </row>
+        <row>
+         <entry><literal>TABLE_NAME</literal></entry>
+         <entry>text</entry>
+         <entry>the name of table related to error, if any</entry>
+        </row>
+        <row>
+         <entry><literal>SCHEMA_NAME</literal></entry>
+         <entry>text</entry>
+         <entry>the name table's schema related to error, if any</entry>
+        </row>
+        <row>
+         <entry><literal>CONSTRAINT_NAME</literal></entry>
+         <entry>text</entry>
+         <entry>the name of constraint related to error, if any</entry>
+        </row>
+        <row>
+         <entry><literal>CONSTRAINT_SCHEMA</literal></entry>
+         <entry>text</entry>
+         <entry>the constaint's schema related to error, if any</entry>
+        </row>
+        <row>
+         <entry><literal>ROUTINE_NAME</literal></entry>
+         <entry>text</entry>
+         <entry>the name of routine related to error, if any</entry>
+        </row>
+        <row>
+         <entry><literal>ROUTINE_SCHEMA</literal></entry>
+         <entry>text</entry>
+         <entry>the schema of routine related to error, if any</entry>
+        </row>
+        <row>
+         <entry><literal>TRIGGER_NAME</literal></entry>
+         <entry>text</entry>
+         <entry>the name of trigger related to error, if any</entry>
+        </row>
+        <row>
+         <entry><literal>TRIGGER_SCHEMA</literal></entry>
+         <entry>text</entry>
+         <entry>the schema of trigger related to error, if any</entry>
+        </row>
        </tbody>
       </tgroup>
      </table>
@@ -3277,7 +3322,11 @@ RAISE NOTICE 'Calling cs_create_job(%)', v_job_id;
     class="parameter">expression</replaceable> items.  The allowed
     <replaceable class="parameter">option</replaceable> keywords are
     <literal>MESSAGE</>, <literal>DETAIL</>, <literal>HINT</>, and
-    <literal>ERRCODE</>, while each <replaceable
+    , <literal>COLUMN_NAME</>, <literal>TABLE_NAME</>,
+    <literal>SCHEMA_NAME</>, <literal>CONSTRAINT_NAME</>,
+    <literal>CONSTRAINT_SCHEMA</>, <literal>ROUTINE_NAME</>,
+    <literal>ROUTINE_SCHEMA</>, <literal>TRIGGER_NAME</>,
+    <literal>TRIGGER_SCHEMA</> while each <replaceable
     class="parameter">expression</replaceable> can be any string-valued
     expression.
     <literal>MESSAGE</> sets the error message text (this option can't
@@ -3287,7 +3336,15 @@ RAISE NOTICE 'Calling cs_create_job(%)', v_job_id;
     <literal>HINT</> supplies a hint message.
     <literal>ERRCODE</> specifies the error code (SQLSTATE) to report,
     either by condition name as shown in <xref linkend="errcodes-appendix">,
-    or directly as a five-character SQLSTATE code.
+    or directly as a five-character SQLSTATE code. <literal>COLUMN_NAME</>
+    sets the name of column related to error. <literal>TABLE_NAME</>
+    sets the name of table related to error. <literal>SCHEMA_NAME</> sets
+    the schema of table related to error. <literal>CONSTRAINT_NAME</> sets
+    name of constraint. <literal>CONSTRAINT_SCHEMA</> sets a schema of constraint
+    related to error. <literal>ROUTINE_NAME</> sets a name of routine related
+    to error. <literal>ROUTINE_SCHEMA</> sets a schema of routine related to error.
+    <literal>TRIGGER_NAME</> sets a name of trigger related to error.
+    <literal>TRIGGER_SCHEMA</> sets a schema of trigger related to error.
    </para>
 
    <para>
diff --git a/src/pl/plpgsql/src/gram.y b/src/pl/plpgsql/src/gram.y
index c991765..4ad447e 100644
--- a/src/pl/plpgsql/src/gram.y
+++ b/src/pl/plpgsql/src/gram.y
@@ -259,6 +259,15 @@ static	List			*read_raise_options(void);
 %token <keyword>	K_DECLARE
 %token <keyword>	K_DEFAULT
 %token <keyword>	K_DETAIL
+%token <keyword>	K_DIAG_COLUMN_NAME
+%token <keyword>	K_DIAG_TABLE_NAME
+%token <keyword>	K_DIAG_SCHEMA_NAME
+%token <keyword>	K_DIAG_CONSTRAINT_NAME
+%token <keyword>	K_DIAG_CONSTRAINT_SCHEMA
+%token <keyword>	K_DIAG_ROUTINE_NAME
+%token <keyword>	K_DIAG_ROUTINE_SCHEMA
+%token <keyword>	K_DIAG_TRIGGER_NAME
+%token <keyword>	K_DIAG_TRIGGER_SCHEMA
 %token <keyword>	K_DIAGNOSTICS
 %token <keyword>	K_DUMP
 %token <keyword>	K_ELSE
@@ -877,6 +886,15 @@ stmt_getdiag	: K_GET getdiag_area_opt K_DIAGNOSTICS getdiag_list ';'
 								case PLPGSQL_GETDIAG_ERROR_HINT:
 								case PLPGSQL_GETDIAG_RETURNED_SQLSTATE:
 								case PLPGSQL_GETDIAG_MESSAGE_TEXT:
+								case PLPGSQL_GETDIAG_COLUMN_NAME:
+								case PLPGSQL_GETDIAG_TABLE_NAME:
+								case PLPGSQL_GETDIAG_SCHEMA_NAME:
+								case PLPGSQL_GETDIAG_CONSTRAINT_NAME:
+								case PLPGSQL_GETDIAG_CONSTRAINT_SCHEMA:
+								case PLPGSQL_GETDIAG_ROUTINE_NAME:
+								case PLPGSQL_GETDIAG_ROUTINE_SCHEMA:
+								case PLPGSQL_GETDIAG_TRIGGER_NAME:
+								case PLPGSQL_GETDIAG_TRIGGER_SCHEMA:
 									if (!new->is_stacked)
 										ereport(ERROR,
 												(errcode(ERRCODE_SYNTAX_ERROR),
@@ -956,6 +974,33 @@ getdiag_item :
 						else if (tok_is_keyword(tok, &yylval,
 												K_RETURNED_SQLSTATE, "returned_sqlstate"))
 							$$ = PLPGSQL_GETDIAG_RETURNED_SQLSTATE;
+						else if (tok_is_keyword(tok, &yylval,
+												K_DIAG_COLUMN_NAME, "column_name"))
+							$$ = PLPGSQL_GETDIAG_COLUMN_NAME;
+						else if (tok_is_keyword(tok, &yylval,
+												K_DIAG_TABLE_NAME, "table_name"))
+							$$ = PLPGSQL_GETDIAG_TABLE_NAME;
+						else if (tok_is_keyword(tok, &yylval,
+												K_DIAG_SCHEMA_NAME, "schema_name"))
+							$$ = PLPGSQL_GETDIAG_SCHEMA_NAME;
+						else if (tok_is_keyword(tok, &yylval,
+												K_DIAG_CONSTRAINT_NAME, "constraint_name"))
+							$$ = PLPGSQL_GETDIAG_CONSTRAINT_NAME;
+						else if (tok_is_keyword(tok, &yylval,
+												K_DIAG_CONSTRAINT_SCHEMA, "constraint_schema"))
+							$$ = PLPGSQL_GETDIAG_CONSTRAINT_SCHEMA;
+						else if (tok_is_keyword(tok, &yylval,
+												K_DIAG_ROUTINE_NAME, "routine_name"))
+							$$ = PLPGSQL_GETDIAG_ROUTINE_NAME;
+						else if (tok_is_keyword(tok, &yylval,
+												K_DIAG_ROUTINE_SCHEMA, "routine_schema"))
+							$$ = PLPGSQL_GETDIAG_ROUTINE_SCHEMA;
+						else if (tok_is_keyword(tok, &yylval,
+												K_DIAG_TRIGGER_NAME, "trigger_name"))
+							$$ = PLPGSQL_GETDIAG_TRIGGER_NAME;
+						else if (tok_is_keyword(tok, &yylval,
+												K_DIAG_TRIGGER_SCHEMA, "trigger_schema"))
+							$$ = PLPGSQL_GETDIAG_TRIGGER_SCHEMA;
 						else
 							yyerror("unrecognized GET DIAGNOSTICS item");
 					}
@@ -2204,7 +2249,10 @@ unreserved_keyword	:
 				| K_ALIAS
 				| K_ARRAY
 				| K_BACKWARD
+				| K_DIAG_COLUMN_NAME
 				| K_CONSTANT
+				| K_DIAG_CONSTRAINT_NAME
+				| K_DIAG_CONSTRAINT_SCHEMA
 				| K_CURRENT
 				| K_CURSOR
 				| K_DEBUG
@@ -2234,12 +2282,18 @@ unreserved_keyword	:
 				| K_RESULT_OID
 				| K_RETURNED_SQLSTATE
 				| K_REVERSE
+				| K_DIAG_ROUTINE_NAME
+				| K_DIAG_ROUTINE_SCHEMA
 				| K_ROW_COUNT
 				| K_ROWTYPE
+				| K_DIAG_SCHEMA_NAME
 				| K_SCROLL
 				| K_SLICE
 				| K_SQLSTATE
 				| K_STACKED
+				| K_DIAG_TABLE_NAME
+				| K_DIAG_TRIGGER_NAME
+				| K_DIAG_TRIGGER_SCHEMA
 				| K_TYPE
 				| K_USE_COLUMN
 				| K_USE_VARIABLE
@@ -3586,6 +3640,33 @@ read_raise_options(void)
 		else if (tok_is_keyword(tok, &yylval,
 								K_HINT, "hint"))
 			opt->opt_type = PLPGSQL_RAISEOPTION_HINT;
+		else if (tok_is_keyword(tok, &yylval,
+								K_DIAG_COLUMN_NAME, "column_name"))
+			opt->opt_type = PLPGSQL_RAISEOPTION_COLUMN_NAME;
+		else if (tok_is_keyword(tok, &yylval,
+								K_DIAG_TABLE_NAME, "table_name"))
+			opt->opt_type = PLPGSQL_RAISEOPTION_TABLE_NAME;
+		else if (tok_is_keyword(tok, &yylval,
+								K_DIAG_SCHEMA_NAME, "schema_name"))
+			opt->opt_type = PLPGSQL_RAISEOPTION_SCHEMA_NAME;
+		else if (tok_is_keyword(tok, &yylval,
+								K_DIAG_CONSTRAINT_NAME, "constraint_name"))
+			opt->opt_type = PLPGSQL_RAISEOPTION_CONSTRAINT_NAME;
+		else if (tok_is_keyword(tok, &yylval,
+								K_DIAG_CONSTRAINT_SCHEMA, "constraint_schema"))
+			opt->opt_type = PLPGSQL_RAISEOPTION_CONSTRAINT_SCHEMA;
+		else if (tok_is_keyword(tok, &yylval,
+								K_DIAG_ROUTINE_NAME, "routine_name"))
+			opt->opt_type = PLPGSQL_RAISEOPTION_ROUTINE_NAME;
+		else if (tok_is_keyword(tok, &yylval,
+								K_DIAG_ROUTINE_SCHEMA, "routine_schema"))
+			opt->opt_type = PLPGSQL_RAISEOPTION_ROUTINE_SCHEMA;
+		else if (tok_is_keyword(tok, &yylval,
+								K_DIAG_TRIGGER_NAME, "trigger_name"))
+			opt->opt_type = PLPGSQL_RAISEOPTION_TRIGGER_NAME;
+		else if (tok_is_keyword(tok, &yylval,
+								K_DIAG_TRIGGER_SCHEMA, "trigger_schema"))
+			opt->opt_type = PLPGSQL_RAISEOPTION_TRIGGER_SCHEMA;
 		else
 			yyerror("unrecognized RAISE statement option");
 
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index a385b9a..24cc263 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -1489,6 +1489,51 @@ exec_stmt_getdiag(PLpgSQL_execstate *estate, PLpgSQL_stmt_getdiag *stmt)
 									 estate->cur_error->message);
 				break;
 
+			case PLPGSQL_GETDIAG_COLUMN_NAME:
+				exec_assign_c_string(estate, var,
+									 estate->cur_error->column_name);
+				break;
+
+			case PLPGSQL_GETDIAG_TABLE_NAME:
+				exec_assign_c_string(estate, var,
+									 estate->cur_error->table_name);
+				break;
+
+			case PLPGSQL_GETDIAG_SCHEMA_NAME:
+				exec_assign_c_string(estate, var,
+									 estate->cur_error->schema_name);
+				break;
+
+			case PLPGSQL_GETDIAG_CONSTRAINT_NAME:
+				exec_assign_c_string(estate, var,
+									 estate->cur_error->constraint_name);
+				break;
+
+			case PLPGSQL_GETDIAG_CONSTRAINT_SCHEMA:
+				exec_assign_c_string(estate, var,
+									 estate->cur_error->constraint_schema);
+				break;
+
+			case PLPGSQL_GETDIAG_ROUTINE_NAME:
+				exec_assign_c_string(estate, var,
+									 estate->cur_error->routine_name);
+				break;
+
+			case PLPGSQL_GETDIAG_ROUTINE_SCHEMA:
+				exec_assign_c_string(estate, var,
+									 estate->cur_error->routine_schema);
+				break;
+
+			case PLPGSQL_GETDIAG_TRIGGER_NAME:
+				exec_assign_c_string(estate, var,
+									 estate->cur_error->trigger_name);
+				break;
+
+			case PLPGSQL_GETDIAG_TRIGGER_SCHEMA:
+				exec_assign_c_string(estate, var,
+									 estate->cur_error->trigger_schema);
+				break;
+
 			default:
 				elog(ERROR, "unrecognized diagnostic item kind: %d",
 					 diag_item->kind);
@@ -2665,6 +2710,15 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
 	char	   *err_message = NULL;
 	char	   *err_detail = NULL;
 	char	   *err_hint = NULL;
+	char	   *column_name = NULL;
+	char	   *table_name = NULL;
+	char	   *schema_name = NULL;
+	char	   *constraint_name = NULL;
+	char	   *constraint_schema = NULL;
+	char	   *routine_name = NULL;
+	char	   *routine_schema = NULL;
+	char	   *trigger_name = NULL;
+	char	   *trigger_schema = NULL;
 	ListCell   *lc;
 
 	/* RAISE with no parameters: re-throw current exception */
@@ -2804,6 +2858,78 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
 									"HINT")));
 				err_hint = pstrdup(extval);
 				break;
+			case PLPGSQL_RAISEOPTION_COLUMN_NAME:
+				if (column_name)
+					ereport(ERROR,
+							(errcode(ERRCODE_SYNTAX_ERROR),
+							 errmsg("RAISE option already specified: %s",
+									"COLUMN_NAME")));
+				column_name = pstrdup(extval);
+				break;
+			case PLPGSQL_RAISEOPTION_TABLE_NAME:
+				if (table_name)
+					ereport(ERROR,
+							(errcode(ERRCODE_SYNTAX_ERROR),
+							 errmsg("RAISE option already specified: %s",
+									"TABLE_NAME")));
+				table_name = pstrdup(extval);
+				break;
+			case PLPGSQL_RAISEOPTION_SCHEMA_NAME:
+				if (schema_name)
+					ereport(ERROR,
+							(errcode(ERRCODE_SYNTAX_ERROR),
+							 errmsg("RAISE option already specified: %s",
+									"SCHEMA_NAME")));
+				schema_name = pstrdup(extval);
+				break;
+			case PLPGSQL_RAISEOPTION_CONSTRAINT_NAME:
+				if (constraint_name)
+					ereport(ERROR,
+							(errcode(ERRCODE_SYNTAX_ERROR),
+							 errmsg("RAISE option already specified: %s",
+									"CONSTRAINT_NAME")));
+				constraint_name = pstrdup(extval);
+				break;
+			case PLPGSQL_RAISEOPTION_CONSTRAINT_SCHEMA:
+				if (constraint_schema)
+					ereport(ERROR,
+							(errcode(ERRCODE_SYNTAX_ERROR),
+							 errmsg("RAISE option already specified: %s",
+									"CONSTRAINT_SCHEMA")));
+				constraint_schema = pstrdup(extval);
+				break;
+			case PLPGSQL_RAISEOPTION_ROUTINE_NAME:
+				if (routine_name)
+					ereport(ERROR,
+							(errcode(ERRCODE_SYNTAX_ERROR),
+							 errmsg("RAISE option already specified: %s",
+									"ROUTINE_NAME")));
+				routine_name = pstrdup(extval);
+				break;
+			case PLPGSQL_RAISEOPTION_ROUTINE_SCHEMA:
+				if (routine_schema)
+					ereport(ERROR,
+							(errcode(ERRCODE_SYNTAX_ERROR),
+							 errmsg("RAISE option already specified: %s",
+									"ROUTINE_SCHEMA")));
+				routine_schema = pstrdup(extval);
+				break;
+			case PLPGSQL_RAISEOPTION_TRIGGER_NAME:
+				if (trigger_name)
+					ereport(ERROR,
+							(errcode(ERRCODE_SYNTAX_ERROR),
+							 errmsg("RAISE option already specified: %s",
+									"TRIGGER_NAME")));
+				trigger_name = pstrdup(extval);
+				break;
+			case PLPGSQL_RAISEOPTION_TRIGGER_SCHEMA:
+				if (trigger_schema)
+					ereport(ERROR,
+							(errcode(ERRCODE_SYNTAX_ERROR),
+							 errmsg("RAISE option already specified: %s",
+									"TRIGGER_SCHEMA")));
+				trigger_schema = pstrdup(extval);
+				break;
 			default:
 				elog(ERROR, "unrecognized raise option: %d", opt->opt_type);
 		}
@@ -2836,7 +2962,16 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
 			(err_code ? errcode(err_code) : 0,
 			 errmsg_internal("%s", err_message),
 			 (err_detail != NULL) ? errdetail_internal("%s", err_detail) : 0,
-			 (err_hint != NULL) ? errhint("%s", err_hint) : 0));
+			 (err_hint != NULL) ? errhint("%s", err_hint) : 0,
+			 (column_name != NULL) ? erritem(PG_DIAG_COLUMN_NAME, column_name) : 0,
+			 (table_name != NULL) ? erritem(PG_DIAG_TABLE_NAME, table_name) : 0,
+			 (schema_name != NULL) ? erritem(PG_DIAG_SCHEMA_NAME, schema_name) : 0,
+			 (constraint_name != NULL) ? erritem(PG_DIAG_CONSTRAINT_NAME, constraint_name) : 0,
+			 (constraint_schema != NULL) ? erritem(PG_DIAG_CONSTRAINT_SCHEMA, constraint_schema) : 0,
+			 (routine_name != NULL) ? erritem(PG_DIAG_ROUTINE_NAME, routine_name) : 0,
+			 (routine_schema != NULL) ? erritem(PG_DIAG_ROUTINE_SCHEMA, routine_schema) : 0,
+			 (trigger_name != NULL) ? erritem(PG_DIAG_TRIGGER_NAME, trigger_name) : 0,
+			 (trigger_schema != NULL) ? erritem(PG_DIAG_TRIGGER_SCHEMA, trigger_schema) : 0));
 
 	estate->err_text = NULL;	/* un-suppress... */
 
@@ -2848,6 +2983,24 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
 		pfree(err_detail);
 	if (err_hint != NULL)
 		pfree(err_hint);
+	if (column_name != NULL)
+		pfree(column_name);
+	if (table_name != NULL)
+		pfree(table_name);
+	if (schema_name != NULL)
+		pfree(schema_name);
+	if (constraint_name != NULL)
+		pfree(constraint_name);
+	if (constraint_schema != NULL)
+		pfree(constraint_schema);
+	if (routine_name != NULL)
+		pfree(routine_name);
+	if (routine_schema != NULL)
+		pfree(routine_schema);
+	if (trigger_name != NULL)
+		pfree(trigger_name);
+	if (trigger_schema != NULL)
+		pfree(trigger_schema);
 
 	return PLPGSQL_RC_OK;
 }
diff --git a/src/pl/plpgsql/src/pl_funcs.c b/src/pl/plpgsql/src/pl_funcs.c
index b5a72dd..a729e3f 100644
--- a/src/pl/plpgsql/src/pl_funcs.c
+++ b/src/pl/plpgsql/src/pl_funcs.c
@@ -287,6 +287,24 @@ plpgsql_getdiag_kindname(int kind)
 			return "RETURNED_SQLSTATE";
 		case PLPGSQL_GETDIAG_MESSAGE_TEXT:
 			return "MESSAGE_TEXT";
+		case PLPGSQL_GETDIAG_COLUMN_NAME:
+			return "COLUMN_NAME";
+		case PLPGSQL_GETDIAG_TABLE_NAME:
+			return "TABLE_NAME";
+		case PLPGSQL_GETDIAG_SCHEMA_NAME:
+			return "SCHEMA_NAME";
+		case PLPGSQL_GETDIAG_CONSTRAINT_NAME:
+			return "CONSTRAINT_NAME";
+		case PLPGSQL_GETDIAG_CONSTRAINT_SCHEMA:
+			return "CONSTRAINT_SCHEMA";
+		case PLPGSQL_GETDIAG_ROUTINE_NAME:
+			return "ROUTINE_NAME";
+		case PLPGSQL_GETDIAG_ROUTINE_SCHEMA:
+			return "ROUTINE_SCHEMA";
+		case PLPGSQL_GETDIAG_TRIGGER_NAME:
+			return "TRIGGER_NAME";
+		case PLPGSQL_GETDIAG_TRIGGER_SCHEMA:
+			return "TRIGGER_SCHEMA";
 	}
 
 	return "unknown";
@@ -1317,6 +1335,33 @@ dump_raise(PLpgSQL_stmt_raise *stmt)
 				case PLPGSQL_RAISEOPTION_HINT:
 					printf("    HINT = ");
 					break;
+				case PLPGSQL_RAISEOPTION_COLUMN_NAME:
+					printf("    COLUMN_NAME = ");
+					break;
+				case PLPGSQL_RAISEOPTION_TABLE_NAME:
+					printf("    TABLE_NAME = ");
+					break;
+				case PLPGSQL_RAISEOPTION_SCHEMA_NAME:
+					printf("    SCHEMA_NAME = ");
+					break;
+				case PLPGSQL_RAISEOPTION_CONSTRAINT_NAME:
+					printf("    CONSTRAINT_NAME = ");
+					break;
+				case PLPGSQL_RAISEOPTION_CONSTRAINT_SCHEMA:
+					printf("    CONSTRAINT_SCHEMA = ");
+					break;
+				case PLPGSQL_RAISEOPTION_ROUTINE_NAME:
+					printf("    ROUTINE_NAME = ");
+					break;
+				case PLPGSQL_RAISEOPTION_ROUTINE_SCHEMA:
+					printf("    ROUTINE_SCHEMA = ");
+					break;
+				case PLPGSQL_RAISEOPTION_TRIGGER_NAME:
+					printf("    TRIGGER_NAME = ");
+					break;
+				case PLPGSQL_RAISEOPTION_TRIGGER_SCHEMA:
+					printf("    TRIGGER_SCHENA = ");
+					break;
 			}
 			dump_expr(opt->expr);
 			printf("\n");
diff --git a/src/pl/plpgsql/src/pl_scanner.c b/src/pl/plpgsql/src/pl_scanner.c
index ebce3fd..587387e 100644
--- a/src/pl/plpgsql/src/pl_scanner.c
+++ b/src/pl/plpgsql/src/pl_scanner.c
@@ -109,7 +109,10 @@ static const ScanKeyword unreserved_keywords[] = {
 	PG_KEYWORD("alias", K_ALIAS, UNRESERVED_KEYWORD)
 	PG_KEYWORD("array", K_ARRAY, UNRESERVED_KEYWORD)
 	PG_KEYWORD("backward", K_BACKWARD, UNRESERVED_KEYWORD)
+	PG_KEYWORD("column_name", K_DIAG_COLUMN_NAME, UNRESERVED_KEYWORD)
 	PG_KEYWORD("constant", K_CONSTANT, UNRESERVED_KEYWORD)
+	PG_KEYWORD("constraint_name", K_DIAG_CONSTRAINT_NAME, UNRESERVED_KEYWORD)
+	PG_KEYWORD("constraint_schema", K_DIAG_CONSTRAINT_SCHEMA, UNRESERVED_KEYWORD)
 	PG_KEYWORD("current", K_CURRENT, UNRESERVED_KEYWORD)
 	PG_KEYWORD("cursor", K_CURSOR, UNRESERVED_KEYWORD)
 	PG_KEYWORD("debug", K_DEBUG, UNRESERVED_KEYWORD)
@@ -139,12 +142,18 @@ static const ScanKeyword unreserved_keywords[] = {
 	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("routine_name", K_DIAG_ROUTINE_NAME, UNRESERVED_KEYWORD)
+	PG_KEYWORD("routine_schema", K_DIAG_ROUTINE_SCHEMA, UNRESERVED_KEYWORD)
 	PG_KEYWORD("row_count", K_ROW_COUNT, UNRESERVED_KEYWORD)
 	PG_KEYWORD("rowtype", K_ROWTYPE, UNRESERVED_KEYWORD)
+	PG_KEYWORD("schema_name", K_DIAG_SCHEMA_NAME, 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("table_name", K_DIAG_TABLE_NAME, UNRESERVED_KEYWORD)
+	PG_KEYWORD("trigger_name", K_DIAG_TRIGGER_NAME, UNRESERVED_KEYWORD)
+	PG_KEYWORD("trigger_schema", K_DIAG_TRIGGER_SCHEMA, 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)
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index b63f336..5b056f1 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -127,7 +127,16 @@ enum
 	PLPGSQL_GETDIAG_ERROR_DETAIL,
 	PLPGSQL_GETDIAG_ERROR_HINT,
 	PLPGSQL_GETDIAG_RETURNED_SQLSTATE,
-	PLPGSQL_GETDIAG_MESSAGE_TEXT
+	PLPGSQL_GETDIAG_MESSAGE_TEXT,
+	PLPGSQL_GETDIAG_COLUMN_NAME,
+	PLPGSQL_GETDIAG_TABLE_NAME,
+	PLPGSQL_GETDIAG_SCHEMA_NAME,
+	PLPGSQL_GETDIAG_CONSTRAINT_NAME,
+	PLPGSQL_GETDIAG_CONSTRAINT_SCHEMA,
+	PLPGSQL_GETDIAG_ROUTINE_NAME,
+	PLPGSQL_GETDIAG_ROUTINE_SCHEMA,
+	PLPGSQL_GETDIAG_TRIGGER_NAME,
+	PLPGSQL_GETDIAG_TRIGGER_SCHEMA
 };
 
 /* --------
@@ -139,7 +148,16 @@ enum
 	PLPGSQL_RAISEOPTION_ERRCODE,
 	PLPGSQL_RAISEOPTION_MESSAGE,
 	PLPGSQL_RAISEOPTION_DETAIL,
-	PLPGSQL_RAISEOPTION_HINT
+	PLPGSQL_RAISEOPTION_HINT,
+	PLPGSQL_RAISEOPTION_COLUMN_NAME,
+	PLPGSQL_RAISEOPTION_TABLE_NAME,
+	PLPGSQL_RAISEOPTION_SCHEMA_NAME,
+	PLPGSQL_RAISEOPTION_CONSTRAINT_NAME,
+	PLPGSQL_RAISEOPTION_CONSTRAINT_SCHEMA,
+	PLPGSQL_RAISEOPTION_ROUTINE_NAME,
+	PLPGSQL_RAISEOPTION_ROUTINE_SCHEMA,
+	PLPGSQL_RAISEOPTION_TRIGGER_NAME,
+	PLPGSQL_RAISEOPTION_TRIGGER_SCHEMA
 };
 
 /* --------
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
index 1e45919..1632f17 100644
--- a/src/test/regress/expected/plpgsql.out
+++ b/src/test/regress/expected/plpgsql.out
@@ -4719,3 +4719,62 @@ 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);
+create function test_eelog_outer()
+returns void as $$
+declare
+  column_name text;
+  table_name text;
+  schema_name text;
+  constraint_name text;
+  constraint_schema text;
+  routine_name text;
+  routine_schema text;
+  trigger_name text;
+  trigger_schema text;
+begin
+  perform test_eelog_inner();
+exception when others then
+  get stacked diagnostics
+    column_name = column_name,
+    table_name = table_name,
+    schema_name = schema_name,
+    constraint_name = constraint_name,
+    constraint_schema = constraint_schema,
+    routine_name = routine_name,
+    routine_schema = routine_schema,
+    trigger_name = trigger_name,
+    trigger_schema = trigger_schema;
+
+  raise notice 'column name: "%":, table name: "%", schema name: "%"', column_name, table_name, schema_name;
+  raise notice 'constraint name: "%", constraint schema: "%"', constraint_name, constraint_schema;
+  raise notice 'routine name: "%", routine schema: "%"', routine_name, routine_schema;
+  raise notice 'trigger name: "%", trigger schema: "%"', trigger_name, trigger_schema;
+end;
+$$ language plpgsql;
+create function test_eelog_inner()
+returns void as $$
+begin
+  raise exception 'custom exception'
+    using column_name = 'some_column_name',
+          table_name = 'some_table_name',
+          schema_name = 'some_schema_name',
+          constraint_name = 'some_constraint_name',
+          constraint_schema = 'some_constraint_schema',
+          routine_name = 'some_routine',
+          routine_schema = 'some_routine_schema',
+          trigger_name = 'some_trigger_name',
+          trigger_schema = 'some_trigger_schema';
+end;
+$$ language plpgsql;
+select test_eelog_outer();
+NOTICE:  column name: "some_column_name":, table name: "some_table_name", schema name: "some_schema_name"
+NOTICE:  constraint name: "some_constraint_name", constraint schema: "some_constraint_schema"
+NOTICE:  routine name: "some_routine", routine schema: "some_routine_schema"
+NOTICE:  trigger name: "some_trigger_name", trigger schema: "some_trigger_schema"
+ test_eelog_outer 
+------------------
+ 
+(1 row)
+
+drop function test_eelog_outer();
+drop function test_eelog_inner();
diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql
index 2b60b67..8cc7693 100644
--- a/src/test/regress/sql/plpgsql.sql
+++ b/src/test/regress/sql/plpgsql.sql
@@ -3723,3 +3723,57 @@ select testoa(1,2,1); -- fail at update
 
 drop function arrayassign1();
 drop function testoa(x1 int, x2 int, x3 int);
+
+create function test_eelog_outer()
+returns void as $$
+declare
+  column_name text;
+  table_name text;
+  schema_name text;
+  constraint_name text;
+  constraint_schema text;
+  routine_name text;
+  routine_schema text;
+  trigger_name text;
+  trigger_schema text;
+begin
+  perform test_eelog_inner();
+exception when others then
+  get stacked diagnostics
+    column_name = column_name,
+    table_name = table_name,
+    schema_name = schema_name,
+    constraint_name = constraint_name,
+    constraint_schema = constraint_schema,
+    routine_name = routine_name,
+    routine_schema = routine_schema,
+    trigger_name = trigger_name,
+    trigger_schema = trigger_schema;
+
+  raise notice 'column name: "%":, table name: "%", schema name: "%"', column_name, table_name, schema_name;
+  raise notice 'constraint name: "%", constraint schema: "%"', constraint_name, constraint_schema;
+  raise notice 'routine name: "%", routine schema: "%"', routine_name, routine_schema;
+  raise notice 'trigger name: "%", trigger schema: "%"', trigger_name, trigger_schema;
+end;
+$$ language plpgsql;
+
+create function test_eelog_inner()
+returns void as $$
+begin
+  raise exception 'custom exception'
+    using column_name = 'some_column_name',
+          table_name = 'some_table_name',
+          schema_name = 'some_schema_name',
+          constraint_name = 'some_constraint_name',
+          constraint_schema = 'some_constraint_schema',
+          routine_name = 'some_routine',
+          routine_schema = 'some_routine_schema',
+          trigger_name = 'some_trigger_name',
+          trigger_schema = 'some_trigger_schema';
+end;
+$$ language plpgsql;
+
+select test_eelog_outer();
+
+drop function test_eelog_outer();
+drop function test_eelog_inner();