1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-27 12:41:57 +03:00

Expose object name error fields in PL/pgSQL.

Specifically, permit attaching them to the error in RAISE and retrieving
them from a caught error in GET STACKED DIAGNOSTICS.  RAISE enforces
nothing about the content of the fields; for its purposes, they are just
additional string fields.  Consequently, clarify in the protocol and
libpq documentation that the usual relationships between error fields,
like a schema name appearing wherever a table name appears, are not
universal.  This freedom has other applications; consider a FDW
propagating an error from an RDBMS having no schema support.

Back-patch to 9.3, where core support for the error fields was
introduced.  This prevents the confusion of having a release where libpq
exposes the fields and PL/pgSQL does not.

Pavel Stehule, lexical revisions by Noah Misch.
This commit is contained in:
Noah Misch
2013-07-03 07:29:23 -04:00
parent 69e4fd4541
commit 7cd9b1371d
10 changed files with 321 additions and 49 deletions

View File

@ -1569,11 +1569,36 @@ exec_stmt_getdiag(PLpgSQL_execstate *estate, PLpgSQL_stmt_getdiag *stmt)
unpack_sql_state(estate->cur_error->sqlerrcode));
break;
case PLPGSQL_GETDIAG_COLUMN_NAME:
exec_assign_c_string(estate, var,
estate->cur_error->column_name);
break;
case PLPGSQL_GETDIAG_CONSTRAINT_NAME:
exec_assign_c_string(estate, var,
estate->cur_error->constraint_name);
break;
case PLPGSQL_GETDIAG_DATATYPE_NAME:
exec_assign_c_string(estate, var,
estate->cur_error->datatype_name);
break;
case PLPGSQL_GETDIAG_MESSAGE_TEXT:
exec_assign_c_string(estate, var,
estate->cur_error->message);
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;
default:
elog(ERROR, "unrecognized diagnostic item kind: %d",
diag_item->kind);
@ -2799,6 +2824,16 @@ exec_init_tuple_store(PLpgSQL_execstate *estate)
estate->rettupdesc = rsi->expectedDesc;
}
#define SET_RAISE_OPTION_TEXT(opt, name) \
do { \
if (opt) \
ereport(ERROR, \
(errcode(ERRCODE_SYNTAX_ERROR), \
errmsg("RAISE option already specified: %s", \
name))); \
opt = pstrdup(extval); \
} while (0)
/* ----------
* exec_stmt_raise Build a message and throw it with elog()
* ----------
@ -2811,6 +2846,11 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
char *err_message = NULL;
char *err_detail = NULL;
char *err_hint = NULL;
char *err_column = NULL;
char *err_constraint = NULL;
char *err_datatype = NULL;
char *err_table = NULL;
char *err_schema = NULL;
ListCell *lc;
/* RAISE with no parameters: re-throw current exception */
@ -2927,28 +2967,28 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
condname = pstrdup(extval);
break;
case PLPGSQL_RAISEOPTION_MESSAGE:
if (err_message)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("RAISE option already specified: %s",
"MESSAGE")));
err_message = pstrdup(extval);
SET_RAISE_OPTION_TEXT(err_message, "MESSAGE");
break;
case PLPGSQL_RAISEOPTION_DETAIL:
if (err_detail)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("RAISE option already specified: %s",
"DETAIL")));
err_detail = pstrdup(extval);
SET_RAISE_OPTION_TEXT(err_detail, "DETAIL");
break;
case PLPGSQL_RAISEOPTION_HINT:
if (err_hint)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("RAISE option already specified: %s",
"HINT")));
err_hint = pstrdup(extval);
SET_RAISE_OPTION_TEXT(err_hint, "HINT");
break;
case PLPGSQL_RAISEOPTION_COLUMN:
SET_RAISE_OPTION_TEXT(err_column, "COLUMN");
break;
case PLPGSQL_RAISEOPTION_CONSTRAINT:
SET_RAISE_OPTION_TEXT(err_constraint, "CONSTRAINT");
break;
case PLPGSQL_RAISEOPTION_DATATYPE:
SET_RAISE_OPTION_TEXT(err_datatype, "DATATYPE");
break;
case PLPGSQL_RAISEOPTION_TABLE:
SET_RAISE_OPTION_TEXT(err_table, "TABLE");
break;
case PLPGSQL_RAISEOPTION_SCHEMA:
SET_RAISE_OPTION_TEXT(err_schema, "SCHEMA");
break;
default:
elog(ERROR, "unrecognized raise option: %d", opt->opt_type);
@ -2982,7 +3022,17 @@ 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,
(err_column != NULL) ?
err_generic_string(PG_DIAG_COLUMN_NAME, err_column) : 0,
(err_constraint != NULL) ?
err_generic_string(PG_DIAG_CONSTRAINT_NAME, err_constraint) : 0,
(err_datatype != NULL) ?
err_generic_string(PG_DIAG_DATATYPE_NAME, err_datatype) : 0,
(err_table != NULL) ?
err_generic_string(PG_DIAG_TABLE_NAME, err_table) : 0,
(err_schema != NULL) ?
err_generic_string(PG_DIAG_SCHEMA_NAME, err_schema) : 0));
estate->err_text = NULL; /* un-suppress... */
@ -2994,6 +3044,16 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
pfree(err_detail);
if (err_hint != NULL)
pfree(err_hint);
if (err_column != NULL)
pfree(err_column);
if (err_constraint != NULL)
pfree(err_constraint);
if (err_datatype != NULL)
pfree(err_datatype);
if (err_table != NULL)
pfree(err_table);
if (err_schema != NULL)
pfree(err_schema);
return PLPGSQL_RC_OK;
}

View File

@ -285,8 +285,18 @@ plpgsql_getdiag_kindname(int kind)
return "PG_EXCEPTION_HINT";
case PLPGSQL_GETDIAG_RETURNED_SQLSTATE:
return "RETURNED_SQLSTATE";
case PLPGSQL_GETDIAG_COLUMN_NAME:
return "COLUMN_NAME";
case PLPGSQL_GETDIAG_CONSTRAINT_NAME:
return "CONSTRAINT_NAME";
case PLPGSQL_GETDIAG_DATATYPE_NAME:
return "PG_DATATYPE_NAME";
case PLPGSQL_GETDIAG_MESSAGE_TEXT:
return "MESSAGE_TEXT";
case PLPGSQL_GETDIAG_TABLE_NAME:
return "TABLE_NAME";
case PLPGSQL_GETDIAG_SCHEMA_NAME:
return "SCHEMA_NAME";
}
return "unknown";
@ -1317,6 +1327,21 @@ dump_raise(PLpgSQL_stmt_raise *stmt)
case PLPGSQL_RAISEOPTION_HINT:
printf(" HINT = ");
break;
case PLPGSQL_RAISEOPTION_COLUMN:
printf(" COLUMN = ");
break;
case PLPGSQL_RAISEOPTION_CONSTRAINT:
printf(" CONSTRAINT = ");
break;
case PLPGSQL_RAISEOPTION_DATATYPE:
printf(" DATATYPE = ");
break;
case PLPGSQL_RAISEOPTION_TABLE:
printf(" TABLE = ");
break;
case PLPGSQL_RAISEOPTION_SCHEMA:
printf(" SCHEMA = ");
break;
}
dump_expr(opt->expr);
printf("\n");

View File

@ -251,10 +251,15 @@ static List *read_raise_options(void);
%token <keyword> K_CASE
%token <keyword> K_CLOSE
%token <keyword> K_COLLATE
%token <keyword> K_COLUMN
%token <keyword> K_COLUMN_NAME
%token <keyword> K_CONSTANT
%token <keyword> K_CONSTRAINT
%token <keyword> K_CONSTRAINT_NAME
%token <keyword> K_CONTINUE
%token <keyword> K_CURRENT
%token <keyword> K_CURSOR
%token <keyword> K_DATATYPE
%token <keyword> K_DEBUG
%token <keyword> K_DECLARE
%token <keyword> K_DEFAULT
@ -298,6 +303,7 @@ static List *read_raise_options(void);
%token <keyword> K_OPTION
%token <keyword> K_OR
%token <keyword> K_PERFORM
%token <keyword> K_PG_DATATYPE_NAME
%token <keyword> K_PG_EXCEPTION_CONTEXT
%token <keyword> K_PG_EXCEPTION_DETAIL
%token <keyword> K_PG_EXCEPTION_HINT
@ -311,11 +317,15 @@ static List *read_raise_options(void);
%token <keyword> K_REVERSE
%token <keyword> K_ROWTYPE
%token <keyword> K_ROW_COUNT
%token <keyword> K_SCHEMA
%token <keyword> K_SCHEMA_NAME
%token <keyword> K_SCROLL
%token <keyword> K_SLICE
%token <keyword> K_SQLSTATE
%token <keyword> K_STACKED
%token <keyword> K_STRICT
%token <keyword> K_TABLE
%token <keyword> K_TABLE_NAME
%token <keyword> K_THEN
%token <keyword> K_TO
%token <keyword> K_TYPE
@ -896,7 +906,12 @@ stmt_getdiag : K_GET getdiag_area_opt K_DIAGNOSTICS getdiag_list ';'
case PLPGSQL_GETDIAG_ERROR_DETAIL:
case PLPGSQL_GETDIAG_ERROR_HINT:
case PLPGSQL_GETDIAG_RETURNED_SQLSTATE:
case PLPGSQL_GETDIAG_COLUMN_NAME:
case PLPGSQL_GETDIAG_CONSTRAINT_NAME:
case PLPGSQL_GETDIAG_DATATYPE_NAME:
case PLPGSQL_GETDIAG_MESSAGE_TEXT:
case PLPGSQL_GETDIAG_TABLE_NAME:
case PLPGSQL_GETDIAG_SCHEMA_NAME:
if (!new->is_stacked)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
@ -970,9 +985,24 @@ getdiag_item :
else if (tok_is_keyword(tok, &yylval,
K_PG_EXCEPTION_CONTEXT, "pg_exception_context"))
$$ = PLPGSQL_GETDIAG_ERROR_CONTEXT;
else if (tok_is_keyword(tok, &yylval,
K_COLUMN_NAME, "column_name"))
$$ = PLPGSQL_GETDIAG_COLUMN_NAME;
else if (tok_is_keyword(tok, &yylval,
K_CONSTRAINT_NAME, "constraint_name"))
$$ = PLPGSQL_GETDIAG_CONSTRAINT_NAME;
else if (tok_is_keyword(tok, &yylval,
K_PG_DATATYPE_NAME, "pg_datatype_name"))
$$ = PLPGSQL_GETDIAG_DATATYPE_NAME;
else if (tok_is_keyword(tok, &yylval,
K_MESSAGE_TEXT, "message_text"))
$$ = PLPGSQL_GETDIAG_MESSAGE_TEXT;
else if (tok_is_keyword(tok, &yylval,
K_TABLE_NAME, "table_name"))
$$ = PLPGSQL_GETDIAG_TABLE_NAME;
else if (tok_is_keyword(tok, &yylval,
K_SCHEMA_NAME, "schema_name"))
$$ = PLPGSQL_GETDIAG_SCHEMA_NAME;
else if (tok_is_keyword(tok, &yylval,
K_RETURNED_SQLSTATE, "returned_sqlstate"))
$$ = PLPGSQL_GETDIAG_RETURNED_SQLSTATE;
@ -2231,9 +2261,14 @@ unreserved_keyword :
| K_ALIAS
| K_ARRAY
| K_BACKWARD
| K_COLUMN
| K_COLUMN_NAME
| K_CONSTANT
| K_CONSTRAINT
| K_CONSTRAINT_NAME
| K_CURRENT
| K_CURSOR
| K_DATATYPE
| K_DEBUG
| K_DETAIL
| K_DUMP
@ -2252,6 +2287,7 @@ unreserved_keyword :
| K_NO
| K_NOTICE
| K_OPTION
| K_PG_DATATYPE_NAME
| K_PG_EXCEPTION_CONTEXT
| K_PG_EXCEPTION_DETAIL
| K_PG_EXCEPTION_HINT
@ -2263,10 +2299,14 @@ unreserved_keyword :
| K_REVERSE
| K_ROW_COUNT
| K_ROWTYPE
| K_SCHEMA
| K_SCHEMA_NAME
| K_SCROLL
| K_SLICE
| K_SQLSTATE
| K_STACKED
| K_TABLE
| K_TABLE_NAME
| K_TYPE
| K_USE_COLUMN
| K_USE_VARIABLE
@ -3631,6 +3671,21 @@ 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_COLUMN, "column"))
opt->opt_type = PLPGSQL_RAISEOPTION_COLUMN;
else if (tok_is_keyword(tok, &yylval,
K_CONSTRAINT, "constraint"))
opt->opt_type = PLPGSQL_RAISEOPTION_CONSTRAINT;
else if (tok_is_keyword(tok, &yylval,
K_DATATYPE, "datatype"))
opt->opt_type = PLPGSQL_RAISEOPTION_DATATYPE;
else if (tok_is_keyword(tok, &yylval,
K_TABLE, "table"))
opt->opt_type = PLPGSQL_RAISEOPTION_TABLE;
else if (tok_is_keyword(tok, &yylval,
K_SCHEMA, "schema"))
opt->opt_type = PLPGSQL_RAISEOPTION_SCHEMA;
else
yyerror("unrecognized RAISE statement option");

View File

@ -109,9 +109,14 @@ 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", K_COLUMN, UNRESERVED_KEYWORD)
PG_KEYWORD("column_name", K_COLUMN_NAME, UNRESERVED_KEYWORD)
PG_KEYWORD("constant", K_CONSTANT, UNRESERVED_KEYWORD)
PG_KEYWORD("constraint", K_CONSTRAINT, UNRESERVED_KEYWORD)
PG_KEYWORD("constraint_name", K_CONSTRAINT_NAME, UNRESERVED_KEYWORD)
PG_KEYWORD("current", K_CURRENT, UNRESERVED_KEYWORD)
PG_KEYWORD("cursor", K_CURSOR, UNRESERVED_KEYWORD)
PG_KEYWORD("datatype", K_DATATYPE, UNRESERVED_KEYWORD)
PG_KEYWORD("debug", K_DEBUG, UNRESERVED_KEYWORD)
PG_KEYWORD("detail", K_DETAIL, UNRESERVED_KEYWORD)
PG_KEYWORD("dump", K_DUMP, UNRESERVED_KEYWORD)
@ -130,6 +135,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_datatype_name", K_PG_DATATYPE_NAME, 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)
@ -141,10 +147,14 @@ static const ScanKeyword unreserved_keywords[] = {
PG_KEYWORD("reverse", K_REVERSE, UNRESERVED_KEYWORD)
PG_KEYWORD("row_count", K_ROW_COUNT, UNRESERVED_KEYWORD)
PG_KEYWORD("rowtype", K_ROWTYPE, UNRESERVED_KEYWORD)
PG_KEYWORD("schema", K_SCHEMA, UNRESERVED_KEYWORD)
PG_KEYWORD("schema_name", K_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", K_TABLE, UNRESERVED_KEYWORD)
PG_KEYWORD("table_name", K_TABLE_NAME, 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)

View File

@ -128,7 +128,12 @@ enum
PLPGSQL_GETDIAG_ERROR_DETAIL,
PLPGSQL_GETDIAG_ERROR_HINT,
PLPGSQL_GETDIAG_RETURNED_SQLSTATE,
PLPGSQL_GETDIAG_MESSAGE_TEXT
PLPGSQL_GETDIAG_COLUMN_NAME,
PLPGSQL_GETDIAG_CONSTRAINT_NAME,
PLPGSQL_GETDIAG_DATATYPE_NAME,
PLPGSQL_GETDIAG_MESSAGE_TEXT,
PLPGSQL_GETDIAG_TABLE_NAME,
PLPGSQL_GETDIAG_SCHEMA_NAME
};
/* --------
@ -140,7 +145,12 @@ enum
PLPGSQL_RAISEOPTION_ERRCODE,
PLPGSQL_RAISEOPTION_MESSAGE,
PLPGSQL_RAISEOPTION_DETAIL,
PLPGSQL_RAISEOPTION_HINT
PLPGSQL_RAISEOPTION_HINT,
PLPGSQL_RAISEOPTION_COLUMN,
PLPGSQL_RAISEOPTION_CONSTRAINT,
PLPGSQL_RAISEOPTION_DATATYPE,
PLPGSQL_RAISEOPTION_TABLE,
PLPGSQL_RAISEOPTION_SCHEMA
};
/* --------