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();