Commit 7cd9b137 authored by Noah Misch's avatar Noah Misch

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.
parent 69e4fd45
...@@ -2712,9 +2712,9 @@ char *PQresultErrorField(const PGresult *res, int fieldcode); ...@@ -2712,9 +2712,9 @@ char *PQresultErrorField(const PGresult *res, int fieldcode);
<term><symbol>PG_DIAG_TABLE_NAME</></term> <term><symbol>PG_DIAG_TABLE_NAME</></term>
<listitem> <listitem>
<para> <para>
If the error was associated with a specific table, the name of If the error was associated with a specific table, the name of the
the table. (When this field is present, the schema name field table. (Refer to the schema name field for the name of the
provides the name of the table's schema.) table's schema.)
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -2723,9 +2723,9 @@ char *PQresultErrorField(const PGresult *res, int fieldcode); ...@@ -2723,9 +2723,9 @@ char *PQresultErrorField(const PGresult *res, int fieldcode);
<term><symbol>PG_DIAG_COLUMN_NAME</></term> <term><symbol>PG_DIAG_COLUMN_NAME</></term>
<listitem> <listitem>
<para> <para>
If the error was associated with a specific table column, the If the error was associated with a specific table column, the name
name of the column. (When this field is present, the schema of the column. (Refer to the schema and table name fields to
and table name fields identify the table.) identify the table.)
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -2734,9 +2734,9 @@ char *PQresultErrorField(const PGresult *res, int fieldcode); ...@@ -2734,9 +2734,9 @@ char *PQresultErrorField(const PGresult *res, int fieldcode);
<term><symbol>PG_DIAG_DATATYPE_NAME</></term> <term><symbol>PG_DIAG_DATATYPE_NAME</></term>
<listitem> <listitem>
<para> <para>
If the error was associated with a specific data type, the name If the error was associated with a specific data type, the name of
of the data type. (When this field is present, the schema name the data type. (Refer to the schema name field for the name of
field provides the name of the data type's schema.) the data type's schema.)
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -2745,11 +2745,11 @@ char *PQresultErrorField(const PGresult *res, int fieldcode); ...@@ -2745,11 +2745,11 @@ char *PQresultErrorField(const PGresult *res, int fieldcode);
<term><symbol>PG_DIAG_CONSTRAINT_NAME</></term> <term><symbol>PG_DIAG_CONSTRAINT_NAME</></term>
<listitem> <listitem>
<para> <para>
If the error was associated with a specific constraint, If the error was associated with a specific constraint, the name
the name of the constraint. The table or domain that the of the constraint. Refer to fields listed above for the
constraint belongs to is reported using the fields listed associated table or domain. (For this purpose, indexes are
above. (For this purpose, indexes are treated as constraints, treated as constraints, even if they weren't created with
even if they weren't created with constraint syntax.) constraint syntax.)
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -2787,9 +2787,14 @@ char *PQresultErrorField(const PGresult *res, int fieldcode); ...@@ -2787,9 +2787,14 @@ char *PQresultErrorField(const PGresult *res, int fieldcode);
<note> <note>
<para> <para>
The fields for schema name, table name, column name, data type The fields for schema name, table name, column name, data type name,
name, and constraint name are supplied only for a limited number and constraint name are supplied only for a limited number of error
of error types; see <xref linkend="errcodes-appendix">. types; see <xref linkend="errcodes-appendix">. Do not assume that
the presence of any of these fields guarantees the presence of
another field. Core error sources observe the interrelationships
noted above, but user-defined functions may use these fields in other
ways. In the same vein, do not assume that these fields denote
contemporary objects in the current database.
</para> </para>
</note> </note>
......
...@@ -2664,11 +2664,36 @@ GET STACKED DIAGNOSTICS <replaceable>variable</replaceable> = <replaceable>item< ...@@ -2664,11 +2664,36 @@ GET STACKED DIAGNOSTICS <replaceable>variable</replaceable> = <replaceable>item<
<entry>text</entry> <entry>text</entry>
<entry>the SQLSTATE error code of the exception</entry> <entry>the SQLSTATE error code of the exception</entry>
</row> </row>
<row>
<entry><literal>COLUMN_NAME</literal></entry>
<entry>text</entry>
<entry>the name of column related to exception</entry>
</row>
<row>
<entry><literal>CONSTRAINT_NAME</literal></entry>
<entry>text</entry>
<entry>the name of constraint related to exception</entry>
</row>
<row>
<entry><literal>PG_DATATYPE_NAME</literal></entry>
<entry>text</entry>
<entry>the name of datatype related to exception</entry>
</row>
<row> <row>
<entry><literal>MESSAGE_TEXT</literal></entry> <entry><literal>MESSAGE_TEXT</literal></entry>
<entry>text</entry> <entry>text</entry>
<entry>the text of the exception's primary message</entry> <entry>the text of the exception's primary message</entry>
</row> </row>
<row>
<entry><literal>TABLE_NAME</literal></entry>
<entry>text</entry>
<entry>the name of table related to exception</entry>
</row>
<row>
<entry><literal>SCHEMA_NAME</literal></entry>
<entry>text</entry>
<entry>the name of schema related to exception</entry>
</row>
<row> <row>
<entry><literal>PG_EXCEPTION_DETAIL</literal></entry> <entry><literal>PG_EXCEPTION_DETAIL</literal></entry>
<entry>text</entry> <entry>text</entry>
...@@ -3355,6 +3380,17 @@ RAISE NOTICE 'Calling cs_create_job(%)', v_job_id; ...@@ -3355,6 +3380,17 @@ RAISE NOTICE 'Calling cs_create_job(%)', v_job_id;
five-character SQLSTATE code.</para> five-character SQLSTATE code.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><literal>COLUMN</literal></term>
<term><literal>CONSTRAINT</literal></term>
<term><literal>DATATYPE</literal></term>
<term><literal>TABLE</literal></term>
<term><literal>SCHEMA</literal></term>
<listitem>
<para>Supplies the name of a related object.</para>
</listitem>
</varlistentry>
</variablelist> </variablelist>
</para> </para>
......
...@@ -4788,8 +4788,8 @@ message. ...@@ -4788,8 +4788,8 @@ message.
<listitem> <listitem>
<para> <para>
Table name: if the error was associated with a specific table, the Table name: if the error was associated with a specific table, the
name of the table. (When this field is present, the schema name field name of the table. (Refer to the schema name field for the name of
provides the name of the table's schema.) the table's schema.)
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -4801,8 +4801,8 @@ message. ...@@ -4801,8 +4801,8 @@ message.
<listitem> <listitem>
<para> <para>
Column name: if the error was associated with a specific table column, Column name: if the error was associated with a specific table column,
the name of the column. (When this field is present, the schema and the name of the column. (Refer to the schema and table name fields to
table name fields identify the table.) identify the table.)
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -4814,8 +4814,8 @@ message. ...@@ -4814,8 +4814,8 @@ message.
<listitem> <listitem>
<para> <para>
Data type name: if the error was associated with a specific data type, Data type name: if the error was associated with a specific data type,
the name of the data type. (When this field is present, the schema the name of the data type. (Refer to the schema name field for the
name field provides the name of the data type's schema.) name of the data type's schema.)
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -4827,10 +4827,10 @@ message. ...@@ -4827,10 +4827,10 @@ message.
<listitem> <listitem>
<para> <para>
Constraint name: if the error was associated with a specific Constraint name: if the error was associated with a specific
constraint, the name of the constraint. The table or domain that the constraint, the name of the constraint. Refer to fields listed above
constraint belongs to is reported using the fields listed above. (For for the associated table or domain. (For this purpose, indexes are
this purpose, indexes are treated as constraints, even if they weren't treated as constraints, even if they weren't created with constraint
created with constraint syntax.) syntax.)
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -4876,7 +4876,12 @@ message. ...@@ -4876,7 +4876,12 @@ message.
<para> <para>
The fields for schema name, table name, column name, data type name, and The fields for schema name, table name, column name, data type name, and
constraint name are supplied only for a limited number of error types; constraint name are supplied only for a limited number of error types;
see <xref linkend="errcodes-appendix">. see <xref linkend="errcodes-appendix">. Frontends should not assume that
the presence of any of these fields guarantees the presence of another
field. Core error sources observe the interrelationships noted above, but
user-defined functions may use these fields in other ways. In the same
vein, clients should not assume that these fields denote contemporary
objects in the current database.
</para> </para>
</note> </note>
......
...@@ -1569,11 +1569,36 @@ exec_stmt_getdiag(PLpgSQL_execstate *estate, PLpgSQL_stmt_getdiag *stmt) ...@@ -1569,11 +1569,36 @@ exec_stmt_getdiag(PLpgSQL_execstate *estate, PLpgSQL_stmt_getdiag *stmt)
unpack_sql_state(estate->cur_error->sqlerrcode)); unpack_sql_state(estate->cur_error->sqlerrcode));
break; 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: case PLPGSQL_GETDIAG_MESSAGE_TEXT:
exec_assign_c_string(estate, var, exec_assign_c_string(estate, var,
estate->cur_error->message); estate->cur_error->message);
break; 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: default:
elog(ERROR, "unrecognized diagnostic item kind: %d", elog(ERROR, "unrecognized diagnostic item kind: %d",
diag_item->kind); diag_item->kind);
...@@ -2799,6 +2824,16 @@ exec_init_tuple_store(PLpgSQL_execstate *estate) ...@@ -2799,6 +2824,16 @@ exec_init_tuple_store(PLpgSQL_execstate *estate)
estate->rettupdesc = rsi->expectedDesc; 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() * 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) ...@@ -2811,6 +2846,11 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
char *err_message = NULL; char *err_message = NULL;
char *err_detail = NULL; char *err_detail = NULL;
char *err_hint = 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; ListCell *lc;
/* RAISE with no parameters: re-throw current exception */ /* RAISE with no parameters: re-throw current exception */
...@@ -2927,28 +2967,28 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt) ...@@ -2927,28 +2967,28 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
condname = pstrdup(extval); condname = pstrdup(extval);
break; break;
case PLPGSQL_RAISEOPTION_MESSAGE: case PLPGSQL_RAISEOPTION_MESSAGE:
if (err_message) SET_RAISE_OPTION_TEXT(err_message, "MESSAGE");
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("RAISE option already specified: %s",
"MESSAGE")));
err_message = pstrdup(extval);
break; break;
case PLPGSQL_RAISEOPTION_DETAIL: case PLPGSQL_RAISEOPTION_DETAIL:
if (err_detail) SET_RAISE_OPTION_TEXT(err_detail, "DETAIL");
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("RAISE option already specified: %s",
"DETAIL")));
err_detail = pstrdup(extval);
break; break;
case PLPGSQL_RAISEOPTION_HINT: case PLPGSQL_RAISEOPTION_HINT:
if (err_hint) SET_RAISE_OPTION_TEXT(err_hint, "HINT");
ereport(ERROR, break;
(errcode(ERRCODE_SYNTAX_ERROR), case PLPGSQL_RAISEOPTION_COLUMN:
errmsg("RAISE option already specified: %s", SET_RAISE_OPTION_TEXT(err_column, "COLUMN");
"HINT"))); break;
err_hint = pstrdup(extval); 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; break;
default: default:
elog(ERROR, "unrecognized raise option: %d", opt->opt_type); elog(ERROR, "unrecognized raise option: %d", opt->opt_type);
...@@ -2982,7 +3022,17 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt) ...@@ -2982,7 +3022,17 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
(err_code ? errcode(err_code) : 0, (err_code ? errcode(err_code) : 0,
errmsg_internal("%s", err_message), errmsg_internal("%s", err_message),
(err_detail != NULL) ? errdetail_internal("%s", err_detail) : 0, (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... */ estate->err_text = NULL; /* un-suppress... */
...@@ -2994,6 +3044,16 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt) ...@@ -2994,6 +3044,16 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
pfree(err_detail); pfree(err_detail);
if (err_hint != NULL) if (err_hint != NULL)
pfree(err_hint); 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; return PLPGSQL_RC_OK;
} }
......
...@@ -285,8 +285,18 @@ plpgsql_getdiag_kindname(int kind) ...@@ -285,8 +285,18 @@ plpgsql_getdiag_kindname(int kind)
return "PG_EXCEPTION_HINT"; return "PG_EXCEPTION_HINT";
case PLPGSQL_GETDIAG_RETURNED_SQLSTATE: case PLPGSQL_GETDIAG_RETURNED_SQLSTATE:
return "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: case PLPGSQL_GETDIAG_MESSAGE_TEXT:
return "MESSAGE_TEXT"; return "MESSAGE_TEXT";
case PLPGSQL_GETDIAG_TABLE_NAME:
return "TABLE_NAME";
case PLPGSQL_GETDIAG_SCHEMA_NAME:
return "SCHEMA_NAME";
} }
return "unknown"; return "unknown";
...@@ -1317,6 +1327,21 @@ dump_raise(PLpgSQL_stmt_raise *stmt) ...@@ -1317,6 +1327,21 @@ dump_raise(PLpgSQL_stmt_raise *stmt)
case PLPGSQL_RAISEOPTION_HINT: case PLPGSQL_RAISEOPTION_HINT:
printf(" HINT = "); printf(" HINT = ");
break; 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); dump_expr(opt->expr);
printf("\n"); printf("\n");
......
...@@ -251,10 +251,15 @@ static List *read_raise_options(void); ...@@ -251,10 +251,15 @@ static List *read_raise_options(void);
%token <keyword> K_CASE %token <keyword> K_CASE
%token <keyword> K_CLOSE %token <keyword> K_CLOSE
%token <keyword> K_COLLATE %token <keyword> K_COLLATE
%token <keyword> K_COLUMN
%token <keyword> K_COLUMN_NAME
%token <keyword> K_CONSTANT %token <keyword> K_CONSTANT
%token <keyword> K_CONSTRAINT
%token <keyword> K_CONSTRAINT_NAME
%token <keyword> K_CONTINUE %token <keyword> K_CONTINUE
%token <keyword> K_CURRENT %token <keyword> K_CURRENT
%token <keyword> K_CURSOR %token <keyword> K_CURSOR
%token <keyword> K_DATATYPE
%token <keyword> K_DEBUG %token <keyword> K_DEBUG
%token <keyword> K_DECLARE %token <keyword> K_DECLARE
%token <keyword> K_DEFAULT %token <keyword> K_DEFAULT
...@@ -298,6 +303,7 @@ static List *read_raise_options(void); ...@@ -298,6 +303,7 @@ static List *read_raise_options(void);
%token <keyword> K_OPTION %token <keyword> K_OPTION
%token <keyword> K_OR %token <keyword> K_OR
%token <keyword> K_PERFORM %token <keyword> K_PERFORM
%token <keyword> K_PG_DATATYPE_NAME
%token <keyword> K_PG_EXCEPTION_CONTEXT %token <keyword> K_PG_EXCEPTION_CONTEXT
%token <keyword> K_PG_EXCEPTION_DETAIL %token <keyword> K_PG_EXCEPTION_DETAIL
%token <keyword> K_PG_EXCEPTION_HINT %token <keyword> K_PG_EXCEPTION_HINT
...@@ -311,11 +317,15 @@ static List *read_raise_options(void); ...@@ -311,11 +317,15 @@ static List *read_raise_options(void);
%token <keyword> K_REVERSE %token <keyword> K_REVERSE
%token <keyword> K_ROWTYPE %token <keyword> K_ROWTYPE
%token <keyword> K_ROW_COUNT %token <keyword> K_ROW_COUNT
%token <keyword> K_SCHEMA
%token <keyword> K_SCHEMA_NAME
%token <keyword> K_SCROLL %token <keyword> K_SCROLL
%token <keyword> K_SLICE %token <keyword> K_SLICE
%token <keyword> K_SQLSTATE %token <keyword> K_SQLSTATE
%token <keyword> K_STACKED %token <keyword> K_STACKED
%token <keyword> K_STRICT %token <keyword> K_STRICT
%token <keyword> K_TABLE
%token <keyword> K_TABLE_NAME
%token <keyword> K_THEN %token <keyword> K_THEN
%token <keyword> K_TO %token <keyword> K_TO
%token <keyword> K_TYPE %token <keyword> K_TYPE
...@@ -896,7 +906,12 @@ stmt_getdiag : K_GET getdiag_area_opt K_DIAGNOSTICS getdiag_list ';' ...@@ -896,7 +906,12 @@ stmt_getdiag : K_GET getdiag_area_opt K_DIAGNOSTICS getdiag_list ';'
case PLPGSQL_GETDIAG_ERROR_DETAIL: case PLPGSQL_GETDIAG_ERROR_DETAIL:
case PLPGSQL_GETDIAG_ERROR_HINT: case PLPGSQL_GETDIAG_ERROR_HINT:
case PLPGSQL_GETDIAG_RETURNED_SQLSTATE: 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_MESSAGE_TEXT:
case PLPGSQL_GETDIAG_TABLE_NAME:
case PLPGSQL_GETDIAG_SCHEMA_NAME:
if (!new->is_stacked) if (!new->is_stacked)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
...@@ -970,9 +985,24 @@ getdiag_item : ...@@ -970,9 +985,24 @@ getdiag_item :
else if (tok_is_keyword(tok, &yylval, else if (tok_is_keyword(tok, &yylval,
K_PG_EXCEPTION_CONTEXT, "pg_exception_context")) K_PG_EXCEPTION_CONTEXT, "pg_exception_context"))
$$ = PLPGSQL_GETDIAG_ERROR_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, else if (tok_is_keyword(tok, &yylval,
K_MESSAGE_TEXT, "message_text")) K_MESSAGE_TEXT, "message_text"))
$$ = PLPGSQL_GETDIAG_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, else if (tok_is_keyword(tok, &yylval,
K_RETURNED_SQLSTATE, "returned_sqlstate")) K_RETURNED_SQLSTATE, "returned_sqlstate"))
$$ = PLPGSQL_GETDIAG_RETURNED_SQLSTATE; $$ = PLPGSQL_GETDIAG_RETURNED_SQLSTATE;
...@@ -2231,9 +2261,14 @@ unreserved_keyword : ...@@ -2231,9 +2261,14 @@ unreserved_keyword :
| K_ALIAS | K_ALIAS
| K_ARRAY | K_ARRAY
| K_BACKWARD | K_BACKWARD
| K_COLUMN
| K_COLUMN_NAME
| K_CONSTANT | K_CONSTANT
| K_CONSTRAINT
| K_CONSTRAINT_NAME
| K_CURRENT | K_CURRENT
| K_CURSOR | K_CURSOR
| K_DATATYPE
| K_DEBUG | K_DEBUG
| K_DETAIL | K_DETAIL
| K_DUMP | K_DUMP
...@@ -2252,6 +2287,7 @@ unreserved_keyword : ...@@ -2252,6 +2287,7 @@ unreserved_keyword :
| K_NO | K_NO
| K_NOTICE | K_NOTICE
| K_OPTION | K_OPTION
| K_PG_DATATYPE_NAME
| K_PG_EXCEPTION_CONTEXT | K_PG_EXCEPTION_CONTEXT
| K_PG_EXCEPTION_DETAIL | K_PG_EXCEPTION_DETAIL
| K_PG_EXCEPTION_HINT | K_PG_EXCEPTION_HINT
...@@ -2263,10 +2299,14 @@ unreserved_keyword : ...@@ -2263,10 +2299,14 @@ unreserved_keyword :
| K_REVERSE | K_REVERSE
| K_ROW_COUNT | K_ROW_COUNT
| K_ROWTYPE | K_ROWTYPE
| K_SCHEMA
| K_SCHEMA_NAME
| K_SCROLL | K_SCROLL
| K_SLICE | K_SLICE
| K_SQLSTATE | K_SQLSTATE
| K_STACKED | K_STACKED
| K_TABLE
| K_TABLE_NAME
| K_TYPE | K_TYPE
| K_USE_COLUMN | K_USE_COLUMN
| K_USE_VARIABLE | K_USE_VARIABLE
...@@ -3631,6 +3671,21 @@ read_raise_options(void) ...@@ -3631,6 +3671,21 @@ read_raise_options(void)
else if (tok_is_keyword(tok, &yylval, else if (tok_is_keyword(tok, &yylval,
K_HINT, "hint")) K_HINT, "hint"))
opt->opt_type = PLPGSQL_RAISEOPTION_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 else
yyerror("unrecognized RAISE statement option"); yyerror("unrecognized RAISE statement option");
......
...@@ -109,9 +109,14 @@ static const ScanKeyword unreserved_keywords[] = { ...@@ -109,9 +109,14 @@ static const ScanKeyword unreserved_keywords[] = {
PG_KEYWORD("alias", K_ALIAS, UNRESERVED_KEYWORD) PG_KEYWORD("alias", K_ALIAS, UNRESERVED_KEYWORD)
PG_KEYWORD("array", K_ARRAY, UNRESERVED_KEYWORD) PG_KEYWORD("array", K_ARRAY, UNRESERVED_KEYWORD)
PG_KEYWORD("backward", K_BACKWARD, 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("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("current", K_CURRENT, UNRESERVED_KEYWORD)
PG_KEYWORD("cursor", K_CURSOR, 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("debug", K_DEBUG, UNRESERVED_KEYWORD)
PG_KEYWORD("detail", K_DETAIL, UNRESERVED_KEYWORD) PG_KEYWORD("detail", K_DETAIL, UNRESERVED_KEYWORD)
PG_KEYWORD("dump", K_DUMP, UNRESERVED_KEYWORD) PG_KEYWORD("dump", K_DUMP, UNRESERVED_KEYWORD)
...@@ -130,6 +135,7 @@ static const ScanKeyword unreserved_keywords[] = { ...@@ -130,6 +135,7 @@ static const ScanKeyword unreserved_keywords[] = {
PG_KEYWORD("no", K_NO, UNRESERVED_KEYWORD) PG_KEYWORD("no", K_NO, UNRESERVED_KEYWORD)
PG_KEYWORD("notice", K_NOTICE, UNRESERVED_KEYWORD) PG_KEYWORD("notice", K_NOTICE, UNRESERVED_KEYWORD)
PG_KEYWORD("option", K_OPTION, 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_context", K_PG_EXCEPTION_CONTEXT, UNRESERVED_KEYWORD)
PG_KEYWORD("pg_exception_detail", K_PG_EXCEPTION_DETAIL, UNRESERVED_KEYWORD) PG_KEYWORD("pg_exception_detail", K_PG_EXCEPTION_DETAIL, UNRESERVED_KEYWORD)
PG_KEYWORD("pg_exception_hint", K_PG_EXCEPTION_HINT, UNRESERVED_KEYWORD) PG_KEYWORD("pg_exception_hint", K_PG_EXCEPTION_HINT, UNRESERVED_KEYWORD)
...@@ -141,10 +147,14 @@ static const ScanKeyword unreserved_keywords[] = { ...@@ -141,10 +147,14 @@ static const ScanKeyword unreserved_keywords[] = {
PG_KEYWORD("reverse", K_REVERSE, UNRESERVED_KEYWORD) PG_KEYWORD("reverse", K_REVERSE, UNRESERVED_KEYWORD)
PG_KEYWORD("row_count", K_ROW_COUNT, UNRESERVED_KEYWORD) PG_KEYWORD("row_count", K_ROW_COUNT, UNRESERVED_KEYWORD)
PG_KEYWORD("rowtype", K_ROWTYPE, 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("scroll", K_SCROLL, UNRESERVED_KEYWORD)
PG_KEYWORD("slice", K_SLICE, UNRESERVED_KEYWORD) PG_KEYWORD("slice", K_SLICE, UNRESERVED_KEYWORD)
PG_KEYWORD("sqlstate", K_SQLSTATE, UNRESERVED_KEYWORD) PG_KEYWORD("sqlstate", K_SQLSTATE, UNRESERVED_KEYWORD)
PG_KEYWORD("stacked", K_STACKED, 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("type", K_TYPE, UNRESERVED_KEYWORD)
PG_KEYWORD("use_column", K_USE_COLUMN, UNRESERVED_KEYWORD) PG_KEYWORD("use_column", K_USE_COLUMN, UNRESERVED_KEYWORD)
PG_KEYWORD("use_variable", K_USE_VARIABLE, UNRESERVED_KEYWORD) PG_KEYWORD("use_variable", K_USE_VARIABLE, UNRESERVED_KEYWORD)
......
...@@ -128,7 +128,12 @@ enum ...@@ -128,7 +128,12 @@ enum
PLPGSQL_GETDIAG_ERROR_DETAIL, PLPGSQL_GETDIAG_ERROR_DETAIL,
PLPGSQL_GETDIAG_ERROR_HINT, PLPGSQL_GETDIAG_ERROR_HINT,
PLPGSQL_GETDIAG_RETURNED_SQLSTATE, 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 ...@@ -140,7 +145,12 @@ enum
PLPGSQL_RAISEOPTION_ERRCODE, PLPGSQL_RAISEOPTION_ERRCODE,
PLPGSQL_RAISEOPTION_MESSAGE, PLPGSQL_RAISEOPTION_MESSAGE,
PLPGSQL_RAISEOPTION_DETAIL, PLPGSQL_RAISEOPTION_DETAIL,
PLPGSQL_RAISEOPTION_HINT PLPGSQL_RAISEOPTION_HINT,
PLPGSQL_RAISEOPTION_COLUMN,
PLPGSQL_RAISEOPTION_CONSTRAINT,
PLPGSQL_RAISEOPTION_DATATYPE,
PLPGSQL_RAISEOPTION_TABLE,
PLPGSQL_RAISEOPTION_SCHEMA
}; };
/* -------- /* --------
......
...@@ -3974,6 +3974,40 @@ select raise_test(); ...@@ -3974,6 +3974,40 @@ select raise_test();
NOTICE: 22012 NOTICE: 22012
ERROR: substitute message ERROR: substitute message
drop function raise_test(); drop function raise_test();
-- test passing column_name, constraint_name, datatype_name, table_name
-- and schema_name error fields
create or replace function stacked_diagnostics_test() returns void as $$
declare _column_name text;
_constraint_name text;
_datatype_name text;
_table_name text;
_schema_name text;
begin
raise exception using
column = '>>some column name<<',
constraint = '>>some constraint name<<',
datatype = '>>some datatype name<<',
table = '>>some table name<<',
schema = '>>some schema name<<';
exception when others then
get stacked diagnostics
_column_name = column_name,
_constraint_name = constraint_name,
_datatype_name = pg_datatype_name,
_table_name = table_name,
_schema_name = schema_name;
raise notice 'column %, constraint %, type %, table %, schema %',
_column_name, _constraint_name, _datatype_name, _table_name, _schema_name;
end;
$$ language plpgsql;
select stacked_diagnostics_test();
NOTICE: column >>some column name<<, constraint >>some constraint name<<, type >>some datatype name<<, table >>some table name<<, schema >>some schema name<<
stacked_diagnostics_test
--------------------------
(1 row)
drop function stacked_diagnostics_test();
-- test CASE statement -- test CASE statement
create or replace function case_test(bigint) returns text as $$ create or replace function case_test(bigint) returns text as $$
declare a int = 10; declare a int = 10;
......
...@@ -3262,6 +3262,38 @@ select raise_test(); ...@@ -3262,6 +3262,38 @@ select raise_test();
drop function raise_test(); drop function raise_test();
-- test passing column_name, constraint_name, datatype_name, table_name
-- and schema_name error fields
create or replace function stacked_diagnostics_test() returns void as $$
declare _column_name text;
_constraint_name text;
_datatype_name text;
_table_name text;
_schema_name text;
begin
raise exception using
column = '>>some column name<<',
constraint = '>>some constraint name<<',
datatype = '>>some datatype name<<',
table = '>>some table name<<',
schema = '>>some schema name<<';
exception when others then
get stacked diagnostics
_column_name = column_name,
_constraint_name = constraint_name,
_datatype_name = pg_datatype_name,
_table_name = table_name,
_schema_name = schema_name;
raise notice 'column %, constraint %, type %, table %, schema %',
_column_name, _constraint_name, _datatype_name, _table_name, _schema_name;
end;
$$ language plpgsql;
select stacked_diagnostics_test();
drop function stacked_diagnostics_test();
-- test CASE statement -- test CASE statement
create or replace function case_test(bigint) returns text as $$ create or replace function case_test(bigint) returns text as $$
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment