diff --git a/doc/src/sgml/plpgsql.sgml b/doc/src/sgml/plpgsql.sgml
index ba2c57b..a8f9a85 100644
--- a/doc/src/sgml/plpgsql.sgml
+++ b/doc/src/sgml/plpgsql.sgml
@@ -2640,6 +2640,61 @@ GET STACKED DIAGNOSTICS variable = item<
text
line(s) of text describing the call stack
+
+ COLUMN_NAME
+ text
+ the name of column related to error, if any
+
+
+ TABLE_NAME
+ text
+ the name of table related to error, if any
+
+
+ SCHEMA_NAME
+ text
+ the name table's schema related to error, if any
+
+
+ CONSTRAINT_NAME
+ text
+ the name of constraint related to error, if any
+
+
+ CONSTRAINT_TABLE
+ text
+ the table of constraint related to error, if any
+
+
+ CONSTRAINT_SCHEMA
+ text
+ the constaint's schema related to error, if any
+
+
+ ROUTINE_NAME
+ text
+ the name of routine related to error, if any
+
+
+ ROUTINE_SCHEMA
+ text
+ the schema of routine related to error, if any
+
+
+ TRIGGER_NAME
+ text
+ the name of trigger related to error, if any
+
+
+ TRIGGER_TABLE
+ text
+ the table of trigger related to error, if any
+
+
+ TRIGGER_SCHEMA
+ text
+ the schema of trigger related to error, if any
+
@@ -3277,7 +3332,11 @@ RAISE NOTICE 'Calling cs_create_job(%)', v_job_id;
class="parameter">expression items. The allowed
option keywords are
MESSAGE>, DETAIL>, HINT>, and
- ERRCODE>, while each COLUMN_NAME>, TABLE_NAME>,
+ SCHEMA_NAME>, CONSTRAINT_NAME>,
+ CONSTRAINT_TABLE, CONSTRAINT_SCHEMA>,
+ ROUTINE_NAME>, ROUTINE_SCHEMA>, TRIGGER_NAME>,
+ TRIGGER_TABLE, TRIGGER_SCHEMA> while each expression can be any string-valued
expression.
MESSAGE> sets the error message text (this option can't
@@ -3287,7 +3346,17 @@ RAISE NOTICE 'Calling cs_create_job(%)', v_job_id;
HINT> supplies a hint message.
ERRCODE> specifies the error code (SQLSTATE) to report,
either by condition name as shown in ,
- or directly as a five-character SQLSTATE code.
+ or directly as a five-character SQLSTATE code. COLUMN_NAME>
+ sets the name of column related to error. TABLE_NAME>
+ sets the name of table related to error. SCHEMA_NAME> sets
+ the schema of table related to error. CONSTRAINT_NAME> sets
+ name of constraint. CONSTRAINT_TABLE sets a table
+ related to constraint. CONSTRAINT_SCHEMA> sets a schema of constraint
+ related to error. ROUTINE_NAME> sets a name of routine related
+ to error. ROUTINE_SCHEMA> sets a schema of routine related to error.
+ TRIGGER_NAME> sets a name of trigger related to error.
+ TRIGGER_TABLE> sets a table of trigger related to error.
+ TRIGGER_SCHEMA> sets a schema of trigger related to error.
diff --git a/src/pl/plpgsql/src/gram.y b/src/pl/plpgsql/src/gram.y
index 4b2dce8..e0e9970 100644
--- a/src/pl/plpgsql/src/gram.y
+++ b/src/pl/plpgsql/src/gram.y
@@ -259,6 +259,17 @@ static List *read_raise_options(void);
%token K_DECLARE
%token K_DEFAULT
%token K_DETAIL
+%token K_DIAG_COLUMN_NAME
+%token K_DIAG_TABLE_NAME
+%token K_DIAG_SCHEMA_NAME
+%token K_DIAG_CONSTRAINT_NAME
+%token K_DIAG_CONSTRAINT_TABLE
+%token K_DIAG_CONSTRAINT_SCHEMA
+%token K_DIAG_ROUTINE_NAME
+%token K_DIAG_ROUTINE_SCHEMA
+%token K_DIAG_TRIGGER_NAME
+%token K_DIAG_TRIGGER_TABLE
+%token K_DIAG_TRIGGER_SCHEMA
%token K_DIAGNOSTICS
%token K_DUMP
%token K_ELSE
@@ -877,6 +888,17 @@ 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_TABLE:
+ case PLPGSQL_GETDIAG_CONSTRAINT_SCHEMA:
+ case PLPGSQL_GETDIAG_ROUTINE_NAME:
+ case PLPGSQL_GETDIAG_ROUTINE_SCHEMA:
+ case PLPGSQL_GETDIAG_TRIGGER_NAME:
+ case PLPGSQL_GETDIAG_TRIGGER_TABLE:
+ case PLPGSQL_GETDIAG_TRIGGER_SCHEMA:
if (!new->is_stacked)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
@@ -956,6 +978,39 @@ 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_TABLE, "constraint_table"))
+ $$ = PLPGSQL_GETDIAG_CONSTRAINT_TABLE;
+ 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_TABLE, "trigger_table"))
+ $$ = PLPGSQL_GETDIAG_TRIGGER_TABLE;
+ 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 +2259,11 @@ unreserved_keyword :
| K_ALIAS
| K_ARRAY
| K_BACKWARD
+ | K_DIAG_COLUMN_NAME
| K_CONSTANT
+ | K_DIAG_CONSTRAINT_NAME
+ | K_DIAG_CONSTRAINT_TABLE
+ | K_DIAG_CONSTRAINT_SCHEMA
| K_CURRENT
| K_CURSOR
| K_DEBUG
@@ -2234,12 +2293,19 @@ 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_TABLE
+ | K_DIAG_TRIGGER_SCHEMA
| K_TYPE
| K_USE_COLUMN
| K_USE_VARIABLE
@@ -3586,6 +3652,39 @@ 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_TABLE, "constraint_table"))
+ opt->opt_type = PLPGSQL_RAISEOPTION_CONSTRAINT_TABLE;
+ 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_TABLE, "trigger_table"))
+ opt->opt_type = PLPGSQL_RAISEOPTION_TRIGGER_TABLE;
+ 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_comp.c b/src/pl/plpgsql/src/pl_comp.c
index 5d2f818..eb20b7a 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -342,6 +342,9 @@ do_compile(FunctionCallInfo fcinfo,
compile_tmp_cxt = MemoryContextSwitchTo(func_cxt);
function->fn_signature = format_procedure(fcinfo->flinfo->fn_oid);
+ function->fn_name = pstrdup(NameStr(procStruct->proname));
+ function->fn_schema = get_namespace_name(procStruct->pronamespace);
+
function->fn_oid = fcinfo->flinfo->fn_oid;
function->fn_xmin = HeapTupleHeaderGetXmin(procTup->t_data);
function->fn_tid = procTup->t_self;
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 8ca791c..2549d60 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -567,6 +567,9 @@ plpgsql_exec_trigger(PLpgSQL_function *func,
else
elog(ERROR, "unrecognized trigger action: not INSERT, DELETE, or UPDATE");
+ estate.tg_name = trigdata->tg_trigger->tgname;
+ estate.tg_schema = get_namespace_name(RelationGetNamespace(trigdata->tg_relation));
+
/*
* Assign the special tg_ variables
*/
@@ -782,6 +785,22 @@ plpgsql_exec_error_callback(void *arg)
{
PLpgSQL_execstate *estate = (PLpgSQL_execstate *) arg;
+ /*
+ * If we are on top of error callback stack, then set function and
+ * trigger related diagnostics fields.
+ */
+ if (error_context_stack->arg == arg)
+ {
+ erritem(PG_DIAG_ROUTINE_NAME, estate->func->fn_name);
+ erritem(PG_DIAG_ROUTINE_SCHEMA, estate->func->fn_schema);
+
+ if (estate->func->fn_is_trigger)
+ {
+ erritem(PG_DIAG_TRIGGER_NAME, estate->tg_name);
+ erritem(PG_DIAG_TRIGGER_SCHEMA, estate->tg_schema);
+ }
+ }
+
/* if we are doing RAISE, don't report its location */
if (estate->err_text == raise_skip_msg)
return;
@@ -1489,6 +1508,61 @@ 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_TABLE:
+ exec_assign_c_string(estate, var,
+ estate->cur_error->constraint_table);
+ 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_TABLE:
+ exec_assign_c_string(estate, var,
+ estate->cur_error->trigger_table);
+ 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);
@@ -2666,6 +2740,17 @@ 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_table = NULL;
+ char *constraint_schema = NULL;
+ char *routine_name = NULL;
+ char *routine_schema = NULL;
+ char *trigger_name = NULL;
+ char *trigger_table = NULL;
+ char *trigger_schema = NULL;
ListCell *lc;
/* RAISE with no parameters: re-throw current exception */
@@ -2805,6 +2890,94 @@ 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_TABLE:
+ if (constraint_table)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("RAISE option already specified: %s",
+ "CONSTRAINT_TABLE")));
+ constraint_table = 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_TABLE:
+ if (trigger_table)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("RAISE option already specified: %s",
+ "TRIGGER_TABLE")));
+ trigger_table = 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);
}
@@ -2837,7 +3010,18 @@ 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_table != NULL) ? erritem(PG_DIAG_CONSTRAINT_TABLE, constraint_table) : 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_table != NULL) ? erritem(PG_DIAG_TRIGGER_TABLE, trigger_table) : 0,
+ (trigger_schema != NULL) ? erritem(PG_DIAG_TRIGGER_SCHEMA, trigger_schema) : 0));
estate->err_text = NULL; /* un-suppress... */
@@ -2849,6 +3033,28 @@ 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_table != NULL)
+ pfree(constraint_table);
+ 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_table != NULL)
+ pfree(trigger_table);
+ if (trigger_schema != NULL)
+ pfree(trigger_schema);
return PLPGSQL_RC_OK;
}
@@ -2930,6 +3136,9 @@ plpgsql_estate_setup(PLpgSQL_execstate *estate,
if ((*plugin_ptr)->func_setup)
((*plugin_ptr)->func_setup) (estate, func);
}
+
+ estate->tg_name = NULL;
+ estate->tg_schema = NULL;
}
/* ----------
diff --git a/src/pl/plpgsql/src/pl_funcs.c b/src/pl/plpgsql/src/pl_funcs.c
index b5a72dd..b76bdca 100644
--- a/src/pl/plpgsql/src/pl_funcs.c
+++ b/src/pl/plpgsql/src/pl_funcs.c
@@ -287,6 +287,28 @@ 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_TABLE:
+ return "CONSTRAINT_TABLE";
+ 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_TABLE:
+ return "TRIGGER_TABLE";
+ case PLPGSQL_GETDIAG_TRIGGER_SCHEMA:
+ return "TRIGGER_SCHEMA";
}
return "unknown";
@@ -1317,6 +1339,39 @@ 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_TABLE:
+ printf(" CONSTRAINT_TABLE = ");
+ 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_TABLE:
+ printf(" TRIGGER_TABLE = ");
+ break;
+ case PLPGSQL_RAISEOPTION_TRIGGER_SCHEMA:
+ printf(" TRIGGER_SCHEMA = ");
+ 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..600f294 100644
--- a/src/pl/plpgsql/src/pl_scanner.c
+++ b/src/pl/plpgsql/src/pl_scanner.c
@@ -109,7 +109,11 @@ 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("constraint_table", K_DIAG_CONSTRAINT_TABLE, 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 +143,19 @@ 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("trigger_table", K_DIAG_TRIGGER_TABLE, 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..cac98e1 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -127,7 +127,18 @@ 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_TABLE,
+ PLPGSQL_GETDIAG_CONSTRAINT_SCHEMA,
+ PLPGSQL_GETDIAG_ROUTINE_NAME,
+ PLPGSQL_GETDIAG_ROUTINE_SCHEMA,
+ PLPGSQL_GETDIAG_TRIGGER_NAME,
+ PLPGSQL_GETDIAG_TRIGGER_TABLE,
+ PLPGSQL_GETDIAG_TRIGGER_SCHEMA
};
/* --------
@@ -139,7 +150,18 @@ 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_TABLE,
+ PLPGSQL_RAISEOPTION_CONSTRAINT_SCHEMA,
+ PLPGSQL_RAISEOPTION_ROUTINE_NAME,
+ PLPGSQL_RAISEOPTION_ROUTINE_SCHEMA,
+ PLPGSQL_RAISEOPTION_TRIGGER_NAME,
+ PLPGSQL_RAISEOPTION_TRIGGER_TABLE,
+ PLPGSQL_RAISEOPTION_TRIGGER_SCHEMA
};
/* --------
@@ -679,6 +701,8 @@ typedef struct PLpgSQL_func_hashkey
typedef struct PLpgSQL_function
{ /* Complete compiled function */
char *fn_signature;
+ char *fn_name;
+ char *fn_schema;
Oid fn_oid;
TransactionId fn_xmin;
ItemPointerData fn_tid;
@@ -765,6 +789,10 @@ typedef struct PLpgSQL_execstate
const char *err_text; /* additional state info */
void *plugin_info; /* reserved for use by optional plugin */
+
+ /* trigger description */
+ char *tg_name;
+ char *tg_schema;
} PLpgSQL_execstate;
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
index fb47fa7..92f1d67 100644
--- a/src/test/regress/expected/plpgsql.out
+++ b/src/test/regress/expected/plpgsql.out
@@ -4719,3 +4719,68 @@ 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_table text;
+ constraint_schema text;
+ routine_name text;
+ routine_schema text;
+ trigger_name text;
+ trigger_table 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_table = constraint_table,
+ constraint_schema = constraint_schema,
+ routine_name = routine_name,
+ routine_schema = routine_schema,
+ trigger_name = trigger_name,
+ trigger_table = trigger_table,
+ trigger_schema = trigger_schema;
+
+ raise notice 'column name: "%":, table name: "%", schema name: "%"', column_name, table_name, schema_name;
+ raise notice 'constraint name: "%", constraint table: %, constraint schema: "%"', constraint_name, constraint_table, constraint_schema;
+ raise notice 'routine name: "%", routine schema: "%"', routine_name, routine_schema;
+ raise notice 'trigger name: "%", trigger table: %, trigger schema: "%"', trigger_name, trigger_table, 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_table = 'some_constraint_table',
+ constraint_schema = 'some_constraint_schema',
+ routine_name = 'some_routine',
+ routine_schema = 'some_routine_schema',
+ trigger_name = 'some_trigger_name',
+ trigger_table = 'some_trigger_table',
+ 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 table: some_constraint_table, constraint schema: "some_constraint_schema"
+NOTICE: routine name: "some_routine", routine schema: "some_routine_schema"
+NOTICE: trigger name: "some_trigger_name", trigger table: some_trigger_table, 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..96a3d2e 100644
--- a/src/test/regress/sql/plpgsql.sql
+++ b/src/test/regress/sql/plpgsql.sql
@@ -3723,3 +3723,63 @@ 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_table text;
+ constraint_schema text;
+ routine_name text;
+ routine_schema text;
+ trigger_name text;
+ trigger_table 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_table = constraint_table,
+ constraint_schema = constraint_schema,
+ routine_name = routine_name,
+ routine_schema = routine_schema,
+ trigger_name = trigger_name,
+ trigger_table = trigger_table,
+ trigger_schema = trigger_schema;
+
+ raise notice 'column name: "%":, table name: "%", schema name: "%"', column_name, table_name, schema_name;
+ raise notice 'constraint name: "%", constraint table: %, constraint schema: "%"', constraint_name, constraint_table, constraint_schema;
+ raise notice 'routine name: "%", routine schema: "%"', routine_name, routine_schema;
+ raise notice 'trigger name: "%", trigger table: %, trigger schema: "%"', trigger_name, trigger_table, 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_table = 'some_constraint_table',
+ constraint_schema = 'some_constraint_schema',
+ routine_name = 'some_routine',
+ routine_schema = 'some_routine_schema',
+ trigger_name = 'some_trigger_name',
+ trigger_table = 'some_trigger_table',
+ trigger_schema = 'some_trigger_schema';
+end;
+$$ language plpgsql;
+
+select test_eelog_outer();
+
+drop function test_eelog_outer();
+drop function test_eelog_inner();