Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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

+22-17
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

+36
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

+16-11
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

+79-19
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

+25
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)