From: Alexander Lakhin <exclusion@gmail.com>
To: Michael Paquier <michael@paquier.xyz>
To: pgsql-hackers <pgsql-hackers@postgresql.org>
Cc: Justin Pryzby <pryzby@telsasoft.com>
Subject: Internal error codes triggered by regression tests and user queries, take 2
Date: Wed, 26 Aug 2026 17:00:00 +0300
Message-ID: <94ac928b-8370-4db5-ada5-579a9ebc089d@gmail.com> (raw)
Hello Michael,
Please take a look at the follow-up to [0]. I've prepared a patch to
assign error codes for errors reached by the following queries:
1)
create table notnull_tbl_fail (a serial constraint foo not null constraint bar not null); -- from constraints.sql
ERROR: XX000: conflicting not-null constraint names "foo" and "bar"
LOCATION: transformColumnDefinition, parse_utilcmd.c:800
ERRCODE_INVALID_TABLE_DEFINITION
2)
SELECT satisfies_hash_partition(0, 4, 0, NULL); -- from hash_part.sql
ERROR: XX000: could not open relation with OID 0
LOCATION: relation_open, relation.c:62
ERRCODE_INVALID_PARAMETER_VALUE (also modified try_relation_open() for consistency)
3)
SELECT COUNT(*) = 0 AS ok FROM pg_shmem_allocations_numa; -- from numa.sql
ERROR: XX000: libnuma initialization failed or NUMA is not supported on this platform
LOCATION: pg_get_shmem_allocations_numa, shmem.c:1122
ERRCODE_FEATURE_NOT_SUPPORTED
4)
create table idxpart (a int) partition by range (a);
create table idxpart0 (like idxpart);
alter table idxpart0 add unique (a);
alter table idxpart attach partition idxpart0 default;
alter table only idxpart add primary key (a); -- from indexing.sql
ERROR: XX000: column "a" of table "idxpart0" is not marked NOT NULL
LOCATION: ATPrepAddPrimaryKey, tablecmds.c:9695
ERRCODE_INVALID_TABLE_DEFINITION
5)
CREATE FUNCTION test_pglz_compress(bytea)
RETURNS bytea
AS '.../src/test/regress/regress.so' LANGUAGE C STRICT;
CREATE FUNCTION test_pglz_decompress(bytea, int4, bool)
RETURNS bytea
AS '.../src/test/regress/regress.so' LANGUAGE C STRICT;
SELECT test_pglz_decompress(test_pglz_compress(
decode(repeat('abcd', 100), 'escape')), 500, true); -- compression_pglz.sql:
ERROR: XX000: pglz_decompress failed
LOCATION: test_pglz_decompress, regress.c:1497
ERRCODE_DATA_CORRUPTED (like for "compressed pglz data is corrupt")
With these changes plus
v1-0001-Report-specific-SQLSTATEs-for-stats-restore-error.patch from [1]
applied, `make check` passes without XX000 errors for me. Tested with:
--- a/src/backend/utils/error/elog.c+++ b/src/backend/utils/error/elog.c@@ -498,6 +498,7 @@ errfinish(const char *filename, int lineno, const char *funcname)
elevel = edata->elevel;
+Assert(!(elevel == ERROR && edata->sqlerrcode == ERRCODE_INTERNAL_ERROR));
/*
* Do processing in ErrorContext, which we hope has enough reserved space
* to report an error.
There are also other internal errors produced during `make check-world`,
but I think they should be considered separately, as most of them are too
generic or really internal, like "cache lookup failed for relation xxx"
triggered by intra-grant-inplace.
Besides the above, I've included in the patch assigning error codes to
errors reported by Justin Pryzby at [2], except for the dubious
amvalidate() and pg_read_file with parse_weight (both are already fixed):
6)
select unknownin('');
ERROR: XX000: failed to find conversion function from unknown to text
LOCATION: coerce_type, parse_coerce.c:544
ERRCODE_CANNOT_COERCE (used by other functions in parse_coerce.c)
7)
SELECT pg_catalog.interval( '12 seconds'::interval ,3);
ERROR: XX000: unrecognized interval typmod: 3
LOCATION: AdjustIntervalForTypmod, timestamp.c:1492
ERRCODE_INVALID_PARAMETER_VALUE (like below in the same function)
8)
SELECT pg_describe_object(1,0,1);
ERROR: XX000: unsupported object class: 1
LOCATION: getObjectDescription, objectaddress.c:4317
ERRCODE_WRONG_OBJECT_TYPE
9)
SELECT acldefault('a',0);
ERROR: XX000: unrecognized object type abbreviation: a
LOCATION: acldefault_sql, acl.c:999
ERRCODE_WRONG_OBJECT_TYPE
10)
select float8_regr_intercept(ARRAY[1]);
ERROR: XX000: float8_regr_intercept: expected 8-element float8 array
LOCATION: check_float8_array, float.c:2985
ERRCODE_INVALID_PARAMETER_VALUE
A couple of cases I reported before:
11)
do $$ #print_strict_params XXX $$;
ERROR: XX000: unrecognized print_strict_params option xxx
CONTEXT: compilation of PL/pgSQL function "inline_code_block" near line 1
LOCATION: plpgsql_yyparse, pl_gram.y:396
ERRCODE_SYNTAX_ERROR
12)
select pg_catalog.range_in('', 23, 0);
ERROR: XX000: type 23 is not a range type
LOCATION: get_range_io_data, rangetypes.c:339
ERRCODE_DATATYPE_MISMATCH (like for "data type %s is not an array type")
[0] https://www.postgresql.org/message-id/aozYob22-UJ8CWzk%40paquier.xyz
[1] https://www.postgresql.org/message-id/CAHGQGwHZLiLa9iM7NAiugp1B7CumN94%3DYBeho9t%3DqKJMnTGwMQ%40mail...
[2] https://www.postgresql.org/message-id/20230213135053.GZ1653%40telsasoft.com
Best regards,
Alexander
Attachments:
[text/x-patch] define-missing-errcodes.patch (8.0K, ../94ac928b-8370-4db5-ada5-579a9ebc089d@gmail.com/2-define-missing-errcodes.patch)
download | inline diff:diff --git a/src/backend/access/common/relation.c b/src/backend/access/common/relation.cindex 38b356b8239..ad32bd13d5f 100644--- a/src/backend/access/common/relation.c+++ b/src/backend/access/common/relation.c@@ -59,7 +59,9 @@ relation_open(Oid relationId, LOCKMODE lockmode)
r = RelationIdGetRelation(relationId);
if (!RelationIsValid(r))
- elog(ERROR, "could not open relation with OID %u", relationId);+ ereport(ERROR,+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),+ errmsg("could not open relation with OID %u", relationId)));
/*
* If we didn't get the lock ourselves, assert that caller holds one,
@@ -113,7 +115,9 @@ try_relation_open(Oid relationId, LOCKMODE lockmode)
r = RelationIdGetRelation(relationId);
if (!RelationIsValid(r))
- elog(ERROR, "could not open relation with OID %u", relationId);+ ereport(ERROR,+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),+ errmsg("could not open relation with OID %u", relationId)));
/* If we didn't get the lock ourselves, assert that caller holds one */
Assert(lockmode != NoLock ||
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.cindex 703754a8123..655eeb1b500 100644--- a/src/backend/catalog/objectaddress.c+++ b/src/backend/catalog/objectaddress.c@@ -4314,7 +4314,10 @@ getObjectDescription(const ObjectAddress *object, bool missing_ok)
}
default:
- elog(ERROR, "unsupported object class: %u", object->classId);+ ereport(ERROR,+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),+ errmsg("unsupported object class: %u", object->classId)));+
}
/* an empty buffer is equivalent to no object found */
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.cindex 9b911310f05..4226115ec84 100644--- a/src/backend/commands/tablecmds.c+++ b/src/backend/commands/tablecmds.c@@ -9693,6 +9693,7 @@ ATPrepAddPrimaryKey(List **wqueue, Relation rel, AlterTableCmd *cmd,
tup = findNotNullConstraint(childrelid, strVal(column));
if (!tup)
ereport(ERROR,
+ errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("column \"%s\" of table \"%s\" is not marked NOT NULL",
strVal(column), get_rel_name(childrelid)));
/* verify it's good enough */
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.cindex d3240f4b265..46e66990ac1 100644--- a/src/backend/parser/parse_coerce.c+++ b/src/backend/parser/parse_coerce.c@@ -541,8 +541,12 @@ coerce_type(ParseState *pstate, Node *node,
return (Node *) r;
}
/* If we get here, caller blew it */
- elog(ERROR, "failed to find conversion function from %s to %s",- format_type_be(inputTypeId), format_type_be(targetTypeId));+ ereport(ERROR,+ (errcode(ERRCODE_CANNOT_COERCE),+ errmsg("failed to find conversion function from %s to %s",+ format_type_be(inputTypeId), format_type_be(targetTypeId))));++
return NULL; /* keep compiler quiet */
}
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.cindex 640e1c4f5a4..abfe449f895 100644--- a/src/backend/parser/parse_utilcmd.c+++ b/src/backend/parser/parse_utilcmd.c@@ -797,8 +797,10 @@ transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
if (constraint->conname &&
notnull_constraint->conname &&
strcmp(notnull_constraint->conname, constraint->conname) != 0)
- elog(ERROR, "conflicting not-null constraint names \"%s\" and \"%s\"",- notnull_constraint->conname, constraint->conname);+ ereport(ERROR,+ errcode(ERRCODE_INVALID_TABLE_DEFINITION),+ errmsg("conflicting not-null constraint names \"%s\" and \"%s\"",+ notnull_constraint->conname, constraint->conname));
if (notnull_constraint->is_no_inherit != constraint->is_no_inherit)
ereport(ERROR,
diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.cindex 228871d2525..4491aabd9a6 100644--- a/src/backend/storage/ipc/shmem.c+++ b/src/backend/storage/ipc/shmem.c@@ -1119,7 +1119,9 @@ pg_get_shmem_allocations_numa(PG_FUNCTION_ARGS)
Size *nodes;
if (pg_numa_init() == -1)
- elog(ERROR, "libnuma initialization failed or NUMA is not supported on this platform");+ ereport(ERROR,+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),+ errmsg("libnuma initialization failed or NUMA is not supported on this platform")));
InitMaterializedSRF(fcinfo, 0);
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.cindex 25cd5d0296b..2385c1ebbe9 100644--- a/src/backend/utils/adt/acl.c+++ b/src/backend/utils/adt/acl.c@@ -996,7 +996,9 @@ acldefault_sql(PG_FUNCTION_ARGS)
objtype = OBJECT_TYPE;
break;
default:
- elog(ERROR, "unrecognized object type abbreviation: %c", objtypec);+ ereport(ERROR,+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),+ errmsg("unrecognized object type abbreviation: %c", objtypec)));
}
PG_RETURN_ACL_P(acldefault(objtype, owner));
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.cindex fd7a6587132..2a33bc37e81 100644--- a/src/backend/utils/adt/float.c+++ b/src/backend/utils/adt/float.c@@ -2982,7 +2982,10 @@ check_float8_array(ArrayType *transarray, const char *caller, int n)
ARR_DIMS(transarray)[0] != n ||
ARR_HASNULL(transarray) ||
ARR_ELEMTYPE(transarray) != FLOAT8OID)
- elog(ERROR, "%s: expected %d-element float8 array", caller, n);+ ereport(ERROR,+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),+ errmsg("%s: expected %d-element float8 array", caller, n)));+
return (float8 *) ARR_DATA_PTR(transarray);
}
diff --git a/src/backend/utils/adt/rangetypes.c b/src/backend/utils/adt/rangetypes.cindex 84d71761c1b..cedfa458c89 100644--- a/src/backend/utils/adt/rangetypes.c+++ b/src/backend/utils/adt/rangetypes.c@@ -336,7 +336,9 @@ get_range_io_data(FunctionCallInfo fcinfo, Oid rngtypid, IOFuncSelector func)
sizeof(RangeIOData));
cache->typcache = lookup_type_cache(rngtypid, TYPECACHE_RANGE_INFO);
if (cache->typcache->rngelemtype == NULL)
- elog(ERROR, "type %u is not a range type", rngtypid);+ ereport(ERROR,+ (errcode(ERRCODE_DATATYPE_MISMATCH),+ errmsg("type %u is not a range type", rngtypid)));
/* get_type_io_data does more than we need, but is convenient */
get_type_io_data(cache->typcache->rngelemtype->type_id,
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.cindex 9c17ba2f905..06d238024e5 100644--- a/src/backend/utils/adt/timestamp.c+++ b/src/backend/utils/adt/timestamp.c@@ -1489,7 +1489,10 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod,
/* fractional-second rounding will be dealt with below */
}
else
- elog(ERROR, "unrecognized interval typmod: %d", typmod);+ ereport(ERROR,+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),+ errmsg("unrecognized interval typmod: %d", typmod)));+
/* Need to adjust sub-second precision? */
if (precision != INTERVAL_FULL_PRECISION)
diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.yindex 5e14a2d7302..98410ce6fd6 100644--- a/src/pl/plpgsql/src/pl_gram.y+++ b/src/pl/plpgsql/src/pl_gram.y@@ -393,7 +393,10 @@ comp_option : '#' K_OPTION K_DUMP
else if (strcmp($3, "off") == 0)
plpgsql_curr_compile->print_strict_params = false;
else
- elog(ERROR, "unrecognized print_strict_params option %s", $3);+ ereport(ERROR,+ (errcode(ERRCODE_SYNTAX_ERROR),+ errmsg("unrecognized print_strict_params option %s", $3)));+
}
| '#' K_VARIABLE_CONFLICT K_ERROR
{
diff --git a/src/test/regress/regress.c b/src/test/regress/regress.cindex c72ee31cdce..2cd4e17b869 100644--- a/src/test/regress/regress.c+++ b/src/test/regress/regress.c@@ -1494,7 +1494,9 @@ test_pglz_decompress(PG_FUNCTION_ARGS)
dlen = pglz_decompress(source, slen, VARDATA(result),
rawsize, check_complete);
if (dlen < 0)
- elog(ERROR, "pglz_decompress failed");+ ereport(ERROR,+ (errcode(ERRCODE_DATA_CORRUPTED),+ errmsg("pglz_decompress failed")));
SET_VARSIZE(result, dlen + VARHDRSZ);
PG_RETURN_BYTEA_P(result);
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: pgsql-hackers@postgresql.org
Cc: exclusion@gmail.com, michael@paquier.xyz, pryzby@telsasoft.com
Subject: Re: Internal error codes triggered by regression tests and user queries, take 2
In-Reply-To: <94ac928b-8370-4db5-ada5-579a9ebc089d@gmail.com>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox