From 09cecdf285ea9f51aed669f9ea1ba840197d49d0 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sun, 2 Aug 2015 23:49:19 -0400 Subject: [PATCH] Fix a number of places that produced XX000 errors in the regression tests. It's against project policy to use elog() for user-facing errors, or to omit an errcode() selection for errors that aren't supposed to be "can't happen" cases. Fix all the violations of this policy that result in ERRCODE_INTERNAL_ERROR log entries during the standard regression tests, as errors that can reliably be triggered from SQL surely should be considered user-facing. I also looked through all the files touched by this commit and fixed other nearby problems of the same ilk. I do not claim to have fixed all violations of the policy, just the ones in these files. In a few places I also changed existing ERRCODE choices that didn't seem particularly appropriate; mainly replacing ERRCODE_SYNTAX_ERROR by something more specific. Back-patch to 9.5, but no further; changing ERRCODE assignments in stable branches doesn't seem like a good idea. --- contrib/tablefunc/tablefunc.c | 40 +++++++++------ src/backend/access/common/reloptions.c | 19 ++++--- src/backend/access/heap/heapam.c | 8 ++- src/backend/commands/copy.c | 32 ++++++++---- src/backend/commands/vacuum.c | 5 +- src/backend/executor/execQual.c | 6 ++- src/backend/utils/adt/txid.c | 13 +++-- src/pl/plperl/plperl.c | 70 +++++++++++++++++--------- src/pl/plpython/plpy_elog.c | 2 +- src/pl/plpython/plpy_exec.c | 12 +++-- src/pl/tcl/pltcl.c | 51 +++++++++++++------ src/test/regress/expected/txid.out | 10 ++-- src/test/regress/regress.c | 6 ++- 13 files changed, 181 insertions(+), 93 deletions(-) diff --git a/contrib/tablefunc/tablefunc.c b/contrib/tablefunc/tablefunc.c index 8a95d4710b..cb1d029bf5 100644 --- a/contrib/tablefunc/tablefunc.c +++ b/contrib/tablefunc/tablefunc.c @@ -432,7 +432,9 @@ crosstab(PG_FUNCTION_ARGS) break; default: /* result type isn't composite */ - elog(ERROR, "return type must be a row type"); + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("return type must be a row type"))); break; } @@ -1350,7 +1352,9 @@ build_tuplestore_recursively(char *key_fld, appendStringInfo(&chk_current_key, "%s%s%s", branch_delim, current_key, branch_delim); if (strstr(chk_branchstr.data, chk_current_key.data)) - elog(ERROR, "infinite recursion detected"); + ereport(ERROR, + (errcode(ERRCODE_INVALID_RECURSION), + errmsg("infinite recursion detected"))); } /* OK, extend the branch */ @@ -1429,7 +1433,7 @@ validateConnectbyTupleDesc(TupleDesc tupdesc, bool show_branch, bool show_serial { if (tupdesc->natts != (CONNECTBY_NCOLS + serial_column)) ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), + (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("invalid return type"), errdetail("Query-specified return tuple has " \ "wrong number of columns."))); @@ -1438,7 +1442,7 @@ validateConnectbyTupleDesc(TupleDesc tupdesc, bool show_branch, bool show_serial { if (tupdesc->natts != CONNECTBY_NCOLS_NOBRANCH + serial_column) ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), + (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("invalid return type"), errdetail("Query-specified return tuple has " \ "wrong number of columns."))); @@ -1447,14 +1451,14 @@ validateConnectbyTupleDesc(TupleDesc tupdesc, bool show_branch, bool show_serial /* check that the types of the first two columns match */ if (tupdesc->attrs[0]->atttypid != tupdesc->attrs[1]->atttypid) ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), + (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("invalid return type"), errdetail("First two columns must be the same type."))); /* check that the type of the third column is INT4 */ if (tupdesc->attrs[2]->atttypid != INT4OID) ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), + (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("invalid return type"), errdetail("Third column must be type %s.", format_type_be(INT4OID)))); @@ -1462,20 +1466,26 @@ validateConnectbyTupleDesc(TupleDesc tupdesc, bool show_branch, bool show_serial /* check that the type of the fourth column is TEXT if applicable */ if (show_branch && tupdesc->attrs[3]->atttypid != TEXTOID) ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), + (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("invalid return type"), errdetail("Fourth column must be type %s.", format_type_be(TEXTOID)))); /* check that the type of the fifth column is INT4 */ if (show_branch && show_serial && tupdesc->attrs[4]->atttypid != INT4OID) - elog(ERROR, "query-specified return tuple not valid for Connectby: " - "fifth column must be type %s", format_type_be(INT4OID)); + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("query-specified return tuple not valid for Connectby: " + "fifth column must be type %s", + format_type_be(INT4OID)))); /* check that the type of the fifth column is INT4 */ if (!show_branch && show_serial && tupdesc->attrs[3]->atttypid != INT4OID) - elog(ERROR, "query-specified return tuple not valid for Connectby: " - "fourth column must be type %s", format_type_be(INT4OID)); + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("query-specified return tuple not valid for Connectby: " + "fourth column must be type %s", + format_type_be(INT4OID)))); /* OK, the tupdesc is valid for our purposes */ } @@ -1496,7 +1506,7 @@ compatConnectbyTupleDescs(TupleDesc ret_tupdesc, TupleDesc sql_tupdesc) */ if (sql_tupdesc->natts < 2) ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), + (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("invalid return type"), errdetail("Query must return at least two columns."))); @@ -1511,7 +1521,7 @@ compatConnectbyTupleDescs(TupleDesc ret_tupdesc, TupleDesc sql_tupdesc) if (ret_atttypid != sql_atttypid || (ret_atttypmod >= 0 && ret_atttypmod != sql_atttypmod)) ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), + (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("invalid return type"), errdetail("SQL key field type %s does " \ "not match return key field type %s.", @@ -1525,7 +1535,7 @@ compatConnectbyTupleDescs(TupleDesc ret_tupdesc, TupleDesc sql_tupdesc) if (ret_atttypid != sql_atttypid || (ret_atttypmod >= 0 && ret_atttypmod != sql_atttypmod)) ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), + (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("invalid return type"), errdetail("SQL parent key field type %s does " \ "not match return parent key field type %s.", @@ -1556,7 +1566,7 @@ compatCrosstabTupleDescs(TupleDesc ret_tupdesc, TupleDesc sql_tupdesc) sql_atttypid = sql_tupdesc->attrs[0]->atttypid; if (ret_atttypid != sql_atttypid) ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), + (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("invalid return type"), errdetail("SQL rowid datatype does not match " \ "return rowid datatype."))); diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 8176b6a6d4..180f529060 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -484,7 +484,7 @@ allocate_reloption(bits32 kinds, int type, char *name, char *desc) size = sizeof(relopt_string); break; default: - elog(ERROR, "unsupported option type"); + elog(ERROR, "unsupported reloption type %d", type); return NULL; /* keep compiler quiet */ } @@ -1016,7 +1016,8 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, parsed = parse_bool(value, &option->values.bool_val); if (validate && !parsed) ereport(ERROR, - (errmsg("invalid value for boolean option \"%s\": %s", + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid value for boolean option \"%s\": %s", option->gen->name, value))); } break; @@ -1027,12 +1028,14 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, parsed = parse_int(value, &option->values.int_val, 0, NULL); if (validate && !parsed) ereport(ERROR, - (errmsg("invalid value for integer option \"%s\": %s", + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid value for integer option \"%s\": %s", option->gen->name, value))); if (validate && (option->values.int_val < optint->min || option->values.int_val > optint->max)) ereport(ERROR, - (errmsg("value %s out of bounds for option \"%s\"", + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("value %s out of bounds for option \"%s\"", value, option->gen->name), errdetail("Valid values are between \"%d\" and \"%d\".", optint->min, optint->max))); @@ -1045,12 +1048,14 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, parsed = parse_real(value, &option->values.real_val); if (validate && !parsed) ereport(ERROR, - (errmsg("invalid value for floating point option \"%s\": %s", + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid value for floating point option \"%s\": %s", option->gen->name, value))); if (validate && (option->values.real_val < optreal->min || option->values.real_val > optreal->max)) ereport(ERROR, - (errmsg("value %s out of bounds for option \"%s\"", + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("value %s out of bounds for option \"%s\"", value, option->gen->name), errdetail("Valid values are between \"%f\" and \"%f\".", optreal->min, optreal->max))); @@ -1168,7 +1173,7 @@ fillRelOptions(void *rdopts, Size basesize, } break; default: - elog(ERROR, "unrecognized reloption type %c", + elog(ERROR, "unsupported reloption type %d", options[i].gen->type); break; } diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 050efdc480..3701d8e59d 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -2801,7 +2801,9 @@ l1: if (result == HeapTupleInvisible) { UnlockReleaseBuffer(buffer); - elog(ERROR, "attempted to delete invisible tuple"); + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("attempted to delete invisible tuple"))); } else if (result == HeapTupleBeingUpdated && wait) { @@ -3343,7 +3345,9 @@ l2: if (result == HeapTupleInvisible) { UnlockReleaseBuffer(buffer); - elog(ERROR, "attempted to update invisible tuple"); + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("attempted to update invisible tuple"))); } else if (result == HeapTupleBeingUpdated && wait) { diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 47dd3accaf..8db1b35fe8 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -1422,9 +1422,9 @@ BeginCopy(bool is_from, * in any RLS clauses. * * When this happens, we are passed in the relid of the originally - * found relation (which we have locked). As the planner will look - * up the relation again, we double-check here to make sure it found - * the same one that we have locked. + * found relation (which we have locked). As the planner will look up + * the relation again, we double-check here to make sure it found the + * same one that we have locked. */ if (queryRelId != InvalidOid) { @@ -1603,10 +1603,12 @@ ClosePipeToProgram(CopyState cstate) pclose_rc = ClosePipeStream(cstate->copy_file); if (pclose_rc == -1) ereport(ERROR, - (errmsg("could not close pipe to external command: %m"))); + (errcode_for_file_access(), + errmsg("could not close pipe to external command: %m"))); else if (pclose_rc != 0) ereport(ERROR, - (errmsg("program \"%s\" failed", + (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), + errmsg("program \"%s\" failed", cstate->filename), errdetail_internal("%s", wait_result_to_str(pclose_rc)))); } @@ -1703,7 +1705,8 @@ BeginCopyTo(Relation rel, cstate->copy_file = OpenPipeStream(cstate->filename, PG_BINARY_W); if (cstate->copy_file == NULL) ereport(ERROR, - (errmsg("could not execute command \"%s\": %m", + (errcode_for_file_access(), + errmsg("could not execute command \"%s\": %m", cstate->filename))); } else @@ -1730,7 +1733,10 @@ BeginCopyTo(Relation rel, cstate->filename))); if (fstat(fileno(cstate->copy_file), &st)) - elog(ERROR, "could not stat file \"%s\": %m", cstate->filename); + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not stat file \"%s\": %m", + cstate->filename))); if (S_ISDIR(st.st_mode)) ereport(ERROR, @@ -2271,13 +2277,13 @@ CopyFrom(CopyState cstate) { if (!ThereAreNoPriorRegisteredSnapshots() || !ThereAreNoReadyPortals()) ereport(ERROR, - (ERRCODE_INVALID_TRANSACTION_STATE, + (errcode(ERRCODE_INVALID_TRANSACTION_STATE), errmsg("cannot perform FREEZE because of prior transaction activity"))); if (cstate->rel->rd_createSubid != GetCurrentSubTransactionId() && cstate->rel->rd_newRelfilenodeSubid != GetCurrentSubTransactionId()) ereport(ERROR, - (ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("cannot perform FREEZE because the table was not created or truncated in the current subtransaction"))); hi_options |= HEAP_INSERT_FROZEN; @@ -2737,7 +2743,8 @@ BeginCopyFrom(Relation rel, cstate->copy_file = OpenPipeStream(cstate->filename, PG_BINARY_R); if (cstate->copy_file == NULL) ereport(ERROR, - (errmsg("could not execute command \"%s\": %m", + (errcode_for_file_access(), + errmsg("could not execute command \"%s\": %m", cstate->filename))); } else @@ -2752,7 +2759,10 @@ BeginCopyFrom(Relation rel, cstate->filename))); if (fstat(fileno(cstate->copy_file), &st)) - elog(ERROR, "could not stat file \"%s\": %m", cstate->filename); + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not stat file \"%s\": %m", + cstate->filename))); if (S_ISDIR(st.st_mode)) ereport(ERROR, diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index baf66f1e6c..85b0483247 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -180,7 +180,10 @@ vacuum(int options, RangeVar *relation, Oid relid, VacuumParams *params, * calls a hostile index expression that itself calls ANALYZE. */ if (in_vacuum) - elog(ERROR, "%s cannot be executed from VACUUM or ANALYZE", stmttype); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("%s cannot be executed from VACUUM or ANALYZE", + stmttype))); /* * Send info about dead objects to the statistics collector, unless we are diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index 0f911f210b..16bc8fa5f6 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -631,7 +631,8 @@ ExecEvalScalarVar(ExprState *exprstate, ExprContext *econtext, { if (variable->vartype != attr->atttypid) ereport(ERROR, - (errmsg("attribute %d has wrong type", attnum), + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("attribute %d has wrong type", attnum), errdetail("Table has type %s, but query expects %s.", format_type_be(attr->atttypid), format_type_be(variable->vartype)))); @@ -4111,7 +4112,8 @@ ExecEvalFieldSelect(FieldSelectState *fstate, /* As in ExecEvalScalarVar, we should but can't check typmod */ if (fselect->resulttype != attr->atttypid) ereport(ERROR, - (errmsg("attribute %d has wrong type", fieldnum), + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("attribute %d has wrong type", fieldnum), errdetail("Table has type %s, but query expects %s.", format_type_be(attr->atttypid), format_type_be(fselect->resulttype)))); diff --git a/src/backend/utils/adt/txid.c b/src/backend/utils/adt/txid.c index ce1d9abdde..ba4b48298f 100644 --- a/src/backend/utils/adt/txid.c +++ b/src/backend/utils/adt/txid.c @@ -334,8 +334,11 @@ parse_snapshot(const char *str) return buf_finalize(buf); bad_format: - elog(ERROR, "invalid input for txid_snapshot: \"%s\"", str_start); - return NULL; + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for type txid_snapshot: \"%s\"", + str_start))); + return NULL; /* keep compiler quiet */ } /* @@ -526,8 +529,10 @@ txid_snapshot_recv(PG_FUNCTION_ARGS) PG_RETURN_POINTER(snap); bad_format: - elog(ERROR, "invalid snapshot data"); - return (Datum) NULL; + ereport(ERROR, + (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), + errmsg("invalid external txid_snapshot data"))); + PG_RETURN_POINTER(NULL); /* keep compiler quiet */ } /* diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c index 78baaac05d..ae0ba19814 100644 --- a/src/pl/plperl/plperl.c +++ b/src/pl/plperl/plperl.c @@ -640,8 +640,9 @@ select_perl_context(bool trusted) else plperl_untrusted_init(); #else - elog(ERROR, - "cannot allocate multiple Perl interpreters on this platform"); + errmsg(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot allocate multiple Perl interpreters on this platform"))); #endif } @@ -660,7 +661,8 @@ select_perl_context(bool trusted) eval_pv("PostgreSQL::InServer::SPI::bootstrap()", FALSE); if (SvTRUE(ERRSV)) ereport(ERROR, - (errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))), + (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), + errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))), errcontext("while executing PostgreSQL::InServer::SPI::bootstrap"))); /* Fully initialized, so mark the hashtable entry valid */ @@ -834,12 +836,14 @@ plperl_init_interp(void) if (perl_parse(plperl, plperl_init_shared_libs, nargs, embedding, NULL) != 0) ereport(ERROR, - (errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))), + (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), + errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))), errcontext("while parsing Perl initialization"))); if (perl_run(plperl) != 0) ereport(ERROR, - (errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))), + (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), + errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))), errcontext("while running Perl initialization"))); #ifdef PLPERL_RESTORE_LOCALE @@ -952,7 +956,8 @@ plperl_trusted_init(void) eval_pv(PLC_TRUSTED, FALSE); if (SvTRUE(ERRSV)) ereport(ERROR, - (errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))), + (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), + errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))), errcontext("while executing PLC_TRUSTED"))); /* @@ -963,7 +968,8 @@ plperl_trusted_init(void) eval_pv("my $a=chr(0x100); return $a =~ /\\xa9/i", FALSE); if (SvTRUE(ERRSV)) ereport(ERROR, - (errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))), + (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), + errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))), errcontext("while executing utf8fix"))); /* @@ -1002,11 +1008,12 @@ plperl_trusted_init(void) if (plperl_on_plperl_init && *plperl_on_plperl_init) { eval_pv(plperl_on_plperl_init, FALSE); + /* XXX need to find a way to determine a better errcode here */ if (SvTRUE(ERRSV)) ereport(ERROR, - (errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))), + (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), + errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))), errcontext("while executing plperl.on_plperl_init"))); - } } @@ -1025,7 +1032,8 @@ plperl_untrusted_init(void) eval_pv(plperl_on_plperlu_init, FALSE); if (SvTRUE(ERRSV)) ereport(ERROR, - (errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))), + (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), + errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))), errcontext("while executing plperl.on_plperlu_init"))); } } @@ -1382,7 +1390,9 @@ plperl_sv_to_literal(SV *sv, char *fqtypename) isnull; if (!OidIsValid(typid)) - elog(ERROR, "lookup failed for type %s", fqtypename); + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("lookup failed for type %s", fqtypename))); datum = plperl_sv_to_datum(sv, typid, -1, @@ -2059,7 +2069,8 @@ plperl_create_sub(plperl_proc_desc *prodesc, char *s, Oid fn_oid) if (!subref) ereport(ERROR, - (errmsg("didn't get a CODE reference from compiling function \"%s\"", + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("didn't get a CODE reference from compiling function \"%s\"", prodesc->proname))); prodesc->reference = subref; @@ -2147,7 +2158,9 @@ plperl_call_perl_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo) PUTBACK; FREETMPS; LEAVE; - elog(ERROR, "didn't get a return item from function"); + ereport(ERROR, + (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), + errmsg("didn't get a return item from function"))); } if (SvTRUE(ERRSV)) @@ -2156,9 +2169,10 @@ plperl_call_perl_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo) PUTBACK; FREETMPS; LEAVE; - /* XXX need to find a way to assign an errcode here */ + /* XXX need to find a way to determine a better errcode here */ ereport(ERROR, - (errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))))); + (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), + errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))))); } retval = newSVsv(POPs); @@ -2187,7 +2201,9 @@ plperl_call_perl_trigger_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo, TDsv = get_sv("main::_TD", 0); if (!TDsv) - elog(ERROR, "couldn't fetch $_TD"); + ereport(ERROR, + (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), + errmsg("couldn't fetch $_TD"))); save_item(TDsv); /* local $_TD */ sv_setsv(TDsv, td); @@ -2209,7 +2225,9 @@ plperl_call_perl_trigger_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo, PUTBACK; FREETMPS; LEAVE; - elog(ERROR, "didn't get a return item from trigger function"); + ereport(ERROR, + (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), + errmsg("didn't get a return item from trigger function"))); } if (SvTRUE(ERRSV)) @@ -2218,9 +2236,10 @@ plperl_call_perl_trigger_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo, PUTBACK; FREETMPS; LEAVE; - /* XXX need to find a way to assign an errcode here */ + /* XXX need to find a way to determine a better errcode here */ ereport(ERROR, - (errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))))); + (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), + errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))))); } retval = newSVsv(POPs); @@ -2248,7 +2267,9 @@ plperl_call_perl_event_trigger_func(plperl_proc_desc *desc, TDsv = get_sv("main::_TD", 0); if (!TDsv) - elog(ERROR, "couldn't fetch $_TD"); + ereport(ERROR, + (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), + errmsg("couldn't fetch $_TD"))); save_item(TDsv); /* local $_TD */ sv_setsv(TDsv, td); @@ -2266,7 +2287,9 @@ plperl_call_perl_event_trigger_func(plperl_proc_desc *desc, PUTBACK; FREETMPS; LEAVE; - elog(ERROR, "didn't get a return item from trigger function"); + ereport(ERROR, + (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), + errmsg("didn't get a return item from trigger function"))); } if (SvTRUE(ERRSV)) @@ -2275,9 +2298,10 @@ plperl_call_perl_event_trigger_func(plperl_proc_desc *desc, PUTBACK; FREETMPS; LEAVE; - /* XXX need to find a way to assign an errcode here */ + /* XXX need to find a way to determine a better errcode here */ ereport(ERROR, - (errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))))); + (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), + errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))))); } retval = newSVsv(POPs); diff --git a/src/pl/plpython/plpy_elog.c b/src/pl/plpython/plpy_elog.c index 461d68c546..15406d60b9 100644 --- a/src/pl/plpython/plpy_elog.c +++ b/src/pl/plpython/plpy_elog.c @@ -97,7 +97,7 @@ PLy_elog(int elevel, const char *fmt,...) PG_TRY(); { ereport(elevel, - (errcode(sqlerrcode ? sqlerrcode : ERRCODE_INTERNAL_ERROR), + (errcode(sqlerrcode ? sqlerrcode : ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), errmsg_internal("%s", primary ? primary : "no exception data"), (detail) ? errdetail_internal("%s", detail) : 0, (tb_depth > 0 && tbmsg) ? errcontext("%s", tbmsg) : 0, diff --git a/src/pl/plpython/plpy_exec.c b/src/pl/plpython/plpy_exec.c index 8c525c932a..3ccebe403e 100644 --- a/src/pl/plpython/plpy_exec.c +++ b/src/pl/plpython/plpy_exec.c @@ -662,11 +662,13 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata, { if ((plntup = PyDict_GetItemString(pltd, "new")) == NULL) ereport(ERROR, - (errmsg("TD[\"new\"] deleted, cannot modify row"))); + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("TD[\"new\"] deleted, cannot modify row"))); Py_INCREF(plntup); if (!PyDict_Check(plntup)) ereport(ERROR, - (errmsg("TD[\"new\"] is not a dictionary"))); + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("TD[\"new\"] is not a dictionary"))); plkeys = PyDict_Keys(plntup); natts = PyList_Size(plkeys); @@ -690,13 +692,15 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata, else { ereport(ERROR, - (errmsg("TD[\"new\"] dictionary key at ordinal position %d is not a string", i))); + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("TD[\"new\"] dictionary key at ordinal position %d is not a string", i))); plattstr = NULL; /* keep compiler quiet */ } attn = SPI_fnumber(tupdesc, plattstr); if (attn == SPI_ERROR_NOATTRIBUTE) ereport(ERROR, - (errmsg("key \"%s\" found in TD[\"new\"] does not exist as a column in the triggering row", + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("key \"%s\" found in TD[\"new\"] does not exist as a column in the triggering row", plattstr))); atti = attn - 1; diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c index 48a3206da1..edfda5915b 100644 --- a/src/pl/tcl/pltcl.c +++ b/src/pl/tcl/pltcl.c @@ -551,7 +551,8 @@ pltcl_init_load_unknown(Tcl_Interp *interp) if (SPI_processed == 0) { SPI_freetuptable(SPI_tuptable); - elog(WARNING, "module \"unknown\" not found in pltcl_modules"); + ereport(WARNING, + (errmsg("module \"unknown\" not found in pltcl_modules"))); relation_close(pmrel, AccessShareLock); return; } @@ -585,8 +586,10 @@ pltcl_init_load_unknown(Tcl_Interp *interp) if (tcl_rc != TCL_OK) { UTF_BEGIN; - elog(ERROR, "could not load module \"unknown\": %s", - UTF_U2E(Tcl_GetStringResult(interp))); + ereport(ERROR, + (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), + errmsg("could not load module \"unknown\": %s", + UTF_U2E(Tcl_GetStringResult(interp))))); UTF_END; } @@ -1039,8 +1042,10 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS, bool pltrusted) &ret_numvals, &ret_values) != TCL_OK) { UTF_BEGIN; - elog(ERROR, "could not split return value from trigger: %s", - UTF_U2E(Tcl_GetStringResult(interp))); + ereport(ERROR, + (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED), + errmsg("could not split return value from trigger: %s", + UTF_U2E(Tcl_GetStringResult(interp))))); UTF_END; } @@ -1048,7 +1053,9 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS, bool pltrusted) PG_TRY(); { if (ret_numvals % 2 != 0) - elog(ERROR, "invalid return list from trigger - must have even # of elements"); + ereport(ERROR, + (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED), + errmsg("invalid return list from trigger - must have even # of elements"))); modattrs = (int *) palloc(tupdesc->natts * sizeof(int)); modvalues = (Datum *) palloc(tupdesc->natts * sizeof(Datum)); @@ -1082,9 +1089,15 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS, bool pltrusted) ************************************************************/ attnum = SPI_fnumber(tupdesc, ret_name); if (attnum == SPI_ERROR_NOATTRIBUTE) - elog(ERROR, "invalid attribute \"%s\"", ret_name); + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("unrecognized attribute \"%s\"", + ret_name))); if (attnum <= 0) - elog(ERROR, "cannot set system attribute \"%s\"", ret_name); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot set system attribute \"%s\"", + ret_name))); /************************************************************ * Ignore dropped columns @@ -1205,7 +1218,8 @@ throw_tcl_error(Tcl_Interp *interp, const char *proname) econtext = UTF_U2E((char *) Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY)); ereport(ERROR, - (errmsg("%s", emsg), + (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), + errmsg("%s", emsg), errcontext("%s\nin PL/Tcl function \"%s\"", econtext, proname))); UTF_END; @@ -1545,8 +1559,11 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid, free(prodesc->internal_proname); free(prodesc); UTF_BEGIN; - elog(ERROR, "could not create internal procedure \"%s\": %s", - internal_proname, UTF_U2E(Tcl_GetStringResult(interp))); + ereport(ERROR, + (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), + errmsg("could not create internal procedure \"%s\": %s", + internal_proname, + UTF_U2E(Tcl_GetStringResult(interp))))); UTF_END; } @@ -1614,10 +1631,10 @@ pltcl_elog(ClientData cdata, Tcl_Interp *interp, } /* - * For non-error messages, just pass 'em to elog(). We do not expect that - * this will fail, but just on the off chance it does, report the error - * back to Tcl. Note we are assuming that elog() can't have any internal - * failures that are so bad as to require a transaction abort. + * For non-error messages, just pass 'em to ereport(). We do not expect + * that this will fail, but just on the off chance it does, report the + * error back to Tcl. Note we are assuming that ereport() can't have any + * internal failures that are so bad as to require a transaction abort. * * This path is also used for FATAL errors, which aren't going to come * back to us at all. @@ -1626,7 +1643,9 @@ pltcl_elog(ClientData cdata, Tcl_Interp *interp, PG_TRY(); { UTF_BEGIN; - elog(level, "%s", UTF_U2E(argv[2])); + ereport(level, + (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), + errmsg("%s", UTF_U2E(argv[2])))); UTF_END; } PG_CATCH(); diff --git a/src/test/regress/expected/txid.out b/src/test/regress/expected/txid.out index 7750b7b98f..ddd217eb10 100644 --- a/src/test/regress/expected/txid.out +++ b/src/test/regress/expected/txid.out @@ -20,19 +20,19 @@ select '12:16:14,14'::txid_snapshot; -- errors select '31:12:'::txid_snapshot; -ERROR: invalid input for txid_snapshot: "31:12:" +ERROR: invalid input syntax for type txid_snapshot: "31:12:" LINE 1: select '31:12:'::txid_snapshot; ^ select '0:1:'::txid_snapshot; -ERROR: invalid input for txid_snapshot: "0:1:" +ERROR: invalid input syntax for type txid_snapshot: "0:1:" LINE 1: select '0:1:'::txid_snapshot; ^ select '12:13:0'::txid_snapshot; -ERROR: invalid input for txid_snapshot: "12:13:0" +ERROR: invalid input syntax for type txid_snapshot: "12:13:0" LINE 1: select '12:13:0'::txid_snapshot; ^ select '12:16:14,13'::txid_snapshot; -ERROR: invalid input for txid_snapshot: "12:16:14,13" +ERROR: invalid input syntax for type txid_snapshot: "12:16:14,13" LINE 1: select '12:16:14,13'::txid_snapshot; ^ create temp table snapshot_test ( @@ -235,6 +235,6 @@ SELECT txid_snapshot '1:9223372036854775807:3'; (1 row) SELECT txid_snapshot '1:9223372036854775808:3'; -ERROR: invalid input for txid_snapshot: "1:9223372036854775808:3" +ERROR: invalid input syntax for type txid_snapshot: "1:9223372036854775808:3" LINE 1: SELECT txid_snapshot '1:9223372036854775808:3'; ^ diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c index bd31a3d382..476975f391 100644 --- a/src/test/regress/regress.c +++ b/src/test/regress/regress.c @@ -549,8 +549,10 @@ ttdummy(PG_FUNCTION_ARGS) elog(ERROR, "ttdummy (%s): %s must be NOT NULL", relname, args[1]); if (oldon != newon || oldoff != newoff) - elog(ERROR, "ttdummy (%s): you cannot change %s and/or %s columns (use set_ttdummy)", - relname, args[0], args[1]); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("ttdummy (%s): you cannot change %s and/or %s columns (use set_ttdummy)", + relname, args[0], args[1]))); if (newoff != TTDUMMY_INFINITY) {