Skip to content

Commit 7cd9b13

Browse files
committed
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.
1 parent 69e4fd4 commit 7cd9b13

File tree

10 files changed

+321
-49
lines changed

10 files changed

+321
-49
lines changed

doc/src/sgml/libpq.sgml

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2712,9 +2712,9 @@ char *PQresultErrorField(const PGresult *res, int fieldcode);
27122712
<term><symbol>PG_DIAG_TABLE_NAME</></term>
27132713
<listitem>
27142714
<para>
2715-
If the error was associated with a specific table, the name of
2716-
the table. (When this field is present, the schema name field
2717-
provides the name of the table's schema.)
2715+
If the error was associated with a specific table, the name of the
2716+
table. (Refer to the schema name field for the name of the
2717+
table's schema.)
27182718
</para>
27192719
</listitem>
27202720
</varlistentry>
@@ -2723,9 +2723,9 @@ char *PQresultErrorField(const PGresult *res, int fieldcode);
27232723
<term><symbol>PG_DIAG_COLUMN_NAME</></term>
27242724
<listitem>
27252725
<para>
2726-
If the error was associated with a specific table column, the
2727-
name of the column. (When this field is present, the schema
2728-
and table name fields identify the table.)
2726+
If the error was associated with a specific table column, the name
2727+
of the column. (Refer to the schema and table name fields to
2728+
identify the table.)
27292729
</para>
27302730
</listitem>
27312731
</varlistentry>
@@ -2734,9 +2734,9 @@ char *PQresultErrorField(const PGresult *res, int fieldcode);
27342734
<term><symbol>PG_DIAG_DATATYPE_NAME</></term>
27352735
<listitem>
27362736
<para>
2737-
If the error was associated with a specific data type, the name
2738-
of the data type. (When this field is present, the schema name
2739-
field provides the name of the data type's schema.)
2737+
If the error was associated with a specific data type, the name of
2738+
the data type. (Refer to the schema name field for the name of
2739+
the data type's schema.)
27402740
</para>
27412741
</listitem>
27422742
</varlistentry>
@@ -2745,11 +2745,11 @@ char *PQresultErrorField(const PGresult *res, int fieldcode);
27452745
<term><symbol>PG_DIAG_CONSTRAINT_NAME</></term>
27462746
<listitem>
27472747
<para>
2748-
If the error was associated with a specific constraint,
2749-
the name of the constraint. The table or domain that the
2750-
constraint belongs to is reported using the fields listed
2751-
above. (For this purpose, indexes are treated as constraints,
2752-
even if they weren't created with constraint syntax.)
2748+
If the error was associated with a specific constraint, the name
2749+
of the constraint. Refer to fields listed above for the
2750+
associated table or domain. (For this purpose, indexes are
2751+
treated as constraints, even if they weren't created with
2752+
constraint syntax.)
27532753
</para>
27542754
</listitem>
27552755
</varlistentry>
@@ -2787,9 +2787,14 @@ char *PQresultErrorField(const PGresult *res, int fieldcode);
27872787

27882788
<note>
27892789
<para>
2790-
The fields for schema name, table name, column name, data type
2791-
name, and constraint name are supplied only for a limited number
2792-
of error types; see <xref linkend="errcodes-appendix">.
2790+
The fields for schema name, table name, column name, data type name,
2791+
and constraint name are supplied only for a limited number of error
2792+
types; see <xref linkend="errcodes-appendix">. Do not assume that
2793+
the presence of any of these fields guarantees the presence of
2794+
another field. Core error sources observe the interrelationships
2795+
noted above, but user-defined functions may use these fields in other
2796+
ways. In the same vein, do not assume that these fields denote
2797+
contemporary objects in the current database.
27932798
</para>
27942799
</note>
27952800

doc/src/sgml/plpgsql.sgml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2664,11 +2664,36 @@ GET STACKED DIAGNOSTICS <replaceable>variable</replaceable> = <replaceable>item<
26642664
<entry>text</entry>
26652665
<entry>the SQLSTATE error code of the exception</entry>
26662666
</row>
2667+
<row>
2668+
<entry><literal>COLUMN_NAME</literal></entry>
2669+
<entry>text</entry>
2670+
<entry>the name of column related to exception</entry>
2671+
</row>
2672+
<row>
2673+
<entry><literal>CONSTRAINT_NAME</literal></entry>
2674+
<entry>text</entry>
2675+
<entry>the name of constraint related to exception</entry>
2676+
</row>
2677+
<row>
2678+
<entry><literal>PG_DATATYPE_NAME</literal></entry>
2679+
<entry>text</entry>
2680+
<entry>the name of datatype related to exception</entry>
2681+
</row>
26672682
<row>
26682683
<entry><literal>MESSAGE_TEXT</literal></entry>
26692684
<entry>text</entry>
26702685
<entry>the text of the exception's primary message</entry>
26712686
</row>
2687+
<row>
2688+
<entry><literal>TABLE_NAME</literal></entry>
2689+
<entry>text</entry>
2690+
<entry>the name of table related to exception</entry>
2691+
</row>
2692+
<row>
2693+
<entry><literal>SCHEMA_NAME</literal></entry>
2694+
<entry>text</entry>
2695+
<entry>the name of schema related to exception</entry>
2696+
</row>
26722697
<row>
26732698
<entry><literal>PG_EXCEPTION_DETAIL</literal></entry>
26742699
<entry>text</entry>
@@ -3355,6 +3380,17 @@ RAISE NOTICE 'Calling cs_create_job(%)', v_job_id;
33553380
five-character SQLSTATE code.</para>
33563381
</listitem>
33573382
</varlistentry>
3383+
3384+
<varlistentry>
3385+
<term><literal>COLUMN</literal></term>
3386+
<term><literal>CONSTRAINT</literal></term>
3387+
<term><literal>DATATYPE</literal></term>
3388+
<term><literal>TABLE</literal></term>
3389+
<term><literal>SCHEMA</literal></term>
3390+
<listitem>
3391+
<para>Supplies the name of a related object.</para>
3392+
</listitem>
3393+
</varlistentry>
33583394
</variablelist>
33593395
</para>
33603396

doc/src/sgml/protocol.sgml

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4788,8 +4788,8 @@ message.
47884788
<listitem>
47894789
<para>
47904790
Table name: if the error was associated with a specific table, the
4791-
name of the table. (When this field is present, the schema name field
4792-
provides the name of the table's schema.)
4791+
name of the table. (Refer to the schema name field for the name of
4792+
the table's schema.)
47934793
</para>
47944794
</listitem>
47954795
</varlistentry>
@@ -4801,8 +4801,8 @@ message.
48014801
<listitem>
48024802
<para>
48034803
Column name: if the error was associated with a specific table column,
4804-
the name of the column. (When this field is present, the schema and
4805-
table name fields identify the table.)
4804+
the name of the column. (Refer to the schema and table name fields to
4805+
identify the table.)
48064806
</para>
48074807
</listitem>
48084808
</varlistentry>
@@ -4814,8 +4814,8 @@ message.
48144814
<listitem>
48154815
<para>
48164816
Data type name: if the error was associated with a specific data type,
4817-
the name of the data type. (When this field is present, the schema
4818-
name field provides the name of the data type's schema.)
4817+
the name of the data type. (Refer to the schema name field for the
4818+
name of the data type's schema.)
48194819
</para>
48204820
</listitem>
48214821
</varlistentry>
@@ -4827,10 +4827,10 @@ message.
48274827
<listitem>
48284828
<para>
48294829
Constraint name: if the error was associated with a specific
4830-
constraint, the name of the constraint. The table or domain that the
4831-
constraint belongs to is reported using the fields listed above. (For
4832-
this purpose, indexes are treated as constraints, even if they weren't
4833-
created with constraint syntax.)
4830+
constraint, the name of the constraint. Refer to fields listed above
4831+
for the associated table or domain. (For this purpose, indexes are
4832+
treated as constraints, even if they weren't created with constraint
4833+
syntax.)
48344834
</para>
48354835
</listitem>
48364836
</varlistentry>
@@ -4876,7 +4876,12 @@ message.
48764876
<para>
48774877
The fields for schema name, table name, column name, data type name, and
48784878
constraint name are supplied only for a limited number of error types;
4879-
see <xref linkend="errcodes-appendix">.
4879+
see <xref linkend="errcodes-appendix">. Frontends should not assume that
4880+
the presence of any of these fields guarantees the presence of another
4881+
field. Core error sources observe the interrelationships noted above, but
4882+
user-defined functions may use these fields in other ways. In the same
4883+
vein, clients should not assume that these fields denote contemporary
4884+
objects in the current database.
48804885
</para>
48814886
</note>
48824887

src/pl/plpgsql/src/pl_exec.c

Lines changed: 79 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1569,11 +1569,36 @@ exec_stmt_getdiag(PLpgSQL_execstate *estate, PLpgSQL_stmt_getdiag *stmt)
15691569
unpack_sql_state(estate->cur_error->sqlerrcode));
15701570
break;
15711571

1572+
case PLPGSQL_GETDIAG_COLUMN_NAME:
1573+
exec_assign_c_string(estate, var,
1574+
estate->cur_error->column_name);
1575+
break;
1576+
1577+
case PLPGSQL_GETDIAG_CONSTRAINT_NAME:
1578+
exec_assign_c_string(estate, var,
1579+
estate->cur_error->constraint_name);
1580+
break;
1581+
1582+
case PLPGSQL_GETDIAG_DATATYPE_NAME:
1583+
exec_assign_c_string(estate, var,
1584+
estate->cur_error->datatype_name);
1585+
break;
1586+
15721587
case PLPGSQL_GETDIAG_MESSAGE_TEXT:
15731588
exec_assign_c_string(estate, var,
15741589
estate->cur_error->message);
15751590
break;
15761591

1592+
case PLPGSQL_GETDIAG_TABLE_NAME:
1593+
exec_assign_c_string(estate, var,
1594+
estate->cur_error->table_name);
1595+
break;
1596+
1597+
case PLPGSQL_GETDIAG_SCHEMA_NAME:
1598+
exec_assign_c_string(estate, var,
1599+
estate->cur_error->schema_name);
1600+
break;
1601+
15771602
default:
15781603
elog(ERROR, "unrecognized diagnostic item kind: %d",
15791604
diag_item->kind);
@@ -2799,6 +2824,16 @@ exec_init_tuple_store(PLpgSQL_execstate *estate)
27992824
estate->rettupdesc = rsi->expectedDesc;
28002825
}
28012826

2827+
#define SET_RAISE_OPTION_TEXT(opt, name) \
2828+
do { \
2829+
if (opt) \
2830+
ereport(ERROR, \
2831+
(errcode(ERRCODE_SYNTAX_ERROR), \
2832+
errmsg("RAISE option already specified: %s", \
2833+
name))); \
2834+
opt = pstrdup(extval); \
2835+
} while (0)
2836+
28022837
/* ----------
28032838
* exec_stmt_raise Build a message and throw it with elog()
28042839
* ----------
@@ -2811,6 +2846,11 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
28112846
char *err_message = NULL;
28122847
char *err_detail = NULL;
28132848
char *err_hint = NULL;
2849+
char *err_column = NULL;
2850+
char *err_constraint = NULL;
2851+
char *err_datatype = NULL;
2852+
char *err_table = NULL;
2853+
char *err_schema = NULL;
28142854
ListCell *lc;
28152855

28162856
/* RAISE with no parameters: re-throw current exception */
@@ -2927,28 +2967,28 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
29272967
condname = pstrdup(extval);
29282968
break;
29292969
case PLPGSQL_RAISEOPTION_MESSAGE:
2930-
if (err_message)
2931-
ereport(ERROR,
2932-
(errcode(ERRCODE_SYNTAX_ERROR),
2933-
errmsg("RAISE option already specified: %s",
2934-
"MESSAGE")));
2935-
err_message = pstrdup(extval);
2970+
SET_RAISE_OPTION_TEXT(err_message, "MESSAGE");
29362971
break;
29372972
case PLPGSQL_RAISEOPTION_DETAIL:
2938-
if (err_detail)
2939-
ereport(ERROR,
2940-
(errcode(ERRCODE_SYNTAX_ERROR),
2941-
errmsg("RAISE option already specified: %s",
2942-
"DETAIL")));
2943-
err_detail = pstrdup(extval);
2973+
SET_RAISE_OPTION_TEXT(err_detail, "DETAIL");
29442974
break;
29452975
case PLPGSQL_RAISEOPTION_HINT:
2946-
if (err_hint)
2947-
ereport(ERROR,
2948-
(errcode(ERRCODE_SYNTAX_ERROR),
2949-
errmsg("RAISE option already specified: %s",
2950-
"HINT")));
2951-
err_hint = pstrdup(extval);
2976+
SET_RAISE_OPTION_TEXT(err_hint, "HINT");
2977+
break;
2978+
case PLPGSQL_RAISEOPTION_COLUMN:
2979+
SET_RAISE_OPTION_TEXT(err_column, "COLUMN");
2980+
break;
2981+
case PLPGSQL_RAISEOPTION_CONSTRAINT:
2982+
SET_RAISE_OPTION_TEXT(err_constraint, "CONSTRAINT");
2983+
break;
2984+
case PLPGSQL_RAISEOPTION_DATATYPE:
2985+
SET_RAISE_OPTION_TEXT(err_datatype, "DATATYPE");
2986+
break;
2987+
case PLPGSQL_RAISEOPTION_TABLE:
2988+
SET_RAISE_OPTION_TEXT(err_table, "TABLE");
2989+
break;
2990+
case PLPGSQL_RAISEOPTION_SCHEMA:
2991+
SET_RAISE_OPTION_TEXT(err_schema, "SCHEMA");
29522992
break;
29532993
default:
29542994
elog(ERROR, "unrecognized raise option: %d", opt->opt_type);
@@ -2982,7 +3022,17 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
29823022
(err_code ? errcode(err_code) : 0,
29833023
errmsg_internal("%s", err_message),
29843024
(err_detail != NULL) ? errdetail_internal("%s", err_detail) : 0,
2985-
(err_hint != NULL) ? errhint("%s", err_hint) : 0));
3025+
(err_hint != NULL) ? errhint("%s", err_hint) : 0,
3026+
(err_column != NULL) ?
3027+
err_generic_string(PG_DIAG_COLUMN_NAME, err_column) : 0,
3028+
(err_constraint != NULL) ?
3029+
err_generic_string(PG_DIAG_CONSTRAINT_NAME, err_constraint) : 0,
3030+
(err_datatype != NULL) ?
3031+
err_generic_string(PG_DIAG_DATATYPE_NAME, err_datatype) : 0,
3032+
(err_table != NULL) ?
3033+
err_generic_string(PG_DIAG_TABLE_NAME, err_table) : 0,
3034+
(err_schema != NULL) ?
3035+
err_generic_string(PG_DIAG_SCHEMA_NAME, err_schema) : 0));
29863036

29873037
estate->err_text = NULL; /* un-suppress... */
29883038

@@ -2994,6 +3044,16 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
29943044
pfree(err_detail);
29953045
if (err_hint != NULL)
29963046
pfree(err_hint);
3047+
if (err_column != NULL)
3048+
pfree(err_column);
3049+
if (err_constraint != NULL)
3050+
pfree(err_constraint);
3051+
if (err_datatype != NULL)
3052+
pfree(err_datatype);
3053+
if (err_table != NULL)
3054+
pfree(err_table);
3055+
if (err_schema != NULL)
3056+
pfree(err_schema);
29973057

29983058
return PLPGSQL_RC_OK;
29993059
}

src/pl/plpgsql/src/pl_funcs.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,8 +285,18 @@ plpgsql_getdiag_kindname(int kind)
285285
return "PG_EXCEPTION_HINT";
286286
case PLPGSQL_GETDIAG_RETURNED_SQLSTATE:
287287
return "RETURNED_SQLSTATE";
288+
case PLPGSQL_GETDIAG_COLUMN_NAME:
289+
return "COLUMN_NAME";
290+
case PLPGSQL_GETDIAG_CONSTRAINT_NAME:
291+
return "CONSTRAINT_NAME";
292+
case PLPGSQL_GETDIAG_DATATYPE_NAME:
293+
return "PG_DATATYPE_NAME";
288294
case PLPGSQL_GETDIAG_MESSAGE_TEXT:
289295
return "MESSAGE_TEXT";
296+
case PLPGSQL_GETDIAG_TABLE_NAME:
297+
return "TABLE_NAME";
298+
case PLPGSQL_GETDIAG_SCHEMA_NAME:
299+
return "SCHEMA_NAME";
290300
}
291301

292302
return "unknown";
@@ -1317,6 +1327,21 @@ dump_raise(PLpgSQL_stmt_raise *stmt)
13171327
case PLPGSQL_RAISEOPTION_HINT:
13181328
printf(" HINT = ");
13191329
break;
1330+
case PLPGSQL_RAISEOPTION_COLUMN:
1331+
printf(" COLUMN = ");
1332+
break;
1333+
case PLPGSQL_RAISEOPTION_CONSTRAINT:
1334+
printf(" CONSTRAINT = ");
1335+
break;
1336+
case PLPGSQL_RAISEOPTION_DATATYPE:
1337+
printf(" DATATYPE = ");
1338+
break;
1339+
case PLPGSQL_RAISEOPTION_TABLE:
1340+
printf(" TABLE = ");
1341+
break;
1342+
case PLPGSQL_RAISEOPTION_SCHEMA:
1343+
printf(" SCHEMA = ");
1344+
break;
13201345
}
13211346
dump_expr(opt->expr);
13221347
printf("\n");

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy