From f2c741e5a52cd71268891c3d7877878a2a2ce260 Mon Sep 17 00:00:00 2001 From: Ayush Tiwari Date: Fri, 21 Aug 2026 15:37:01 +0530 Subject: [PATCH v2] Fix internal errors reachable from SQL currtid_for_view() ended with an elog() when it could not resolve the view's ctid column to a base relation, which happens for example when the view groups by ctid. Ordinary SQL can reach that, so it should not be reported as XX000 (internal_error). The other unsupported-view checks in the same function report ERRCODE_FEATURE_NOT_SUPPORTED, so match them. (bug #19631) While looking for other instances of the same problem, a few more errors reachable from SQL turned out to have no error code: * varlena.c: unicode_assigned() rejects non-UTF8 server encodings; report that as ERRCODE_FEATURE_NOT_SUPPORTED, since the operation is not supported for the current database encoding. * pg_controldata.c: the pg_control_*() functions raise a control file CRC mismatch, which is ERRCODE_DATA_CORRUPTED. * gist.c: an inner tuple left invalid by a pre-9.1 crash is a corrupt index, so use ERRCODE_INDEX_CORRUPTED, like the checks in gistutil.c. * collationcmds.c: refusing ALTER COLLATION ... REFRESH VERSION for the default collation is ERRCODE_WRONG_OBJECT_TYPE. Add regression coverage for the currtid_for_view() fallback, using SQLSTATE-only error verbosity to verify that it reports 0A000 rather than XX000. No error messages change. Author: Ayush Tiwari Bug: #19631 Reported-by: Zheng Wang Reported-by: Yanjie Zhao Reported-by: Yiyang Liu Discussion: https://postgr.es/m/19631-b443dd6cd8d4e40b@postgresql.org --- Changes in v2: * Use ERRCODE_FEATURE_NOT_SUPPORTED for unicode_assigned(). * Add a regression test for the currtid_for_view() error code. src/backend/access/gist/gist.c | 3 ++- src/backend/commands/collationcmds.c | 3 ++- src/backend/utils/adt/tid.c | 4 +++- src/backend/utils/adt/varlena.c | 3 ++- src/backend/utils/misc/pg_controldata.c | 12 ++++++++---- src/test/regress/expected/tid.out | 8 ++++++++ src/test/regress/sql/tid.sql | 7 +++++++ 7 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c index 8565e225be7..44597793433 100644 --- a/src/backend/access/gist/gist.c +++ b/src/backend/access/gist/gist.c @@ -762,7 +762,8 @@ gistdoinsert(Relation r, IndexTuple itup, Size freespace, */ if (GistTupleIsInvalid(idxtuple)) ereport(ERROR, - (errmsg("index \"%s\" contains an inner tuple marked as invalid", + (errcode(ERRCODE_INDEX_CORRUPTED), + errmsg("index \"%s\" contains an inner tuple marked as invalid", RelationGetRelationName(r)), errdetail("This is caused by an incomplete page split at crash recovery before upgrading to PostgreSQL 9.1."), errhint("Please REINDEX it."))); diff --git a/src/backend/commands/collationcmds.c b/src/backend/commands/collationcmds.c index cfa0e4610d9..92faa60a750 100644 --- a/src/backend/commands/collationcmds.c +++ b/src/backend/commands/collationcmds.c @@ -443,7 +443,8 @@ AlterCollation(AlterCollationStmt *stmt) if (collOid == DEFAULT_COLLATION_OID) ereport(ERROR, - (errmsg("cannot refresh version of default collation"), + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot refresh version of default collation"), /* translator: %s is an SQL command */ errhint("Use %s instead.", "ALTER DATABASE ... REFRESH COLLATION VERSION"))); diff --git a/src/backend/utils/adt/tid.c b/src/backend/utils/adt/tid.c index a97873f91ba..9b2cca0db4d 100644 --- a/src/backend/utils/adt/tid.c +++ b/src/backend/utils/adt/tid.c @@ -432,7 +432,9 @@ currtid_for_view(Relation viewrel, const ItemPointerData *tid) break; } } - elog(ERROR, "currtid cannot handle this view"); + ereport(ERROR, + errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("currtid cannot handle this view")); return NULL; } diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c index f6a41e709ae..1288705baeb 100644 --- a/src/backend/utils/adt/varlena.c +++ b/src/backend/utils/adt/varlena.c @@ -5482,7 +5482,8 @@ unicode_assigned(PG_FUNCTION_ARGS) if (GetDatabaseEncoding() != PG_UTF8) ereport(ERROR, - (errmsg("Unicode categorization can only be performed if server encoding is UTF8"))); + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Unicode categorization can only be performed if server encoding is UTF8"))); /* convert to char32_t */ size = pg_mbstrlen_with_len(VARDATA_ANY(input), VARSIZE_ANY_EXHDR(input)); diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c index 1f47302fe2a..4eac0b33cd1 100644 --- a/src/backend/utils/misc/pg_controldata.c +++ b/src/backend/utils/misc/pg_controldata.c @@ -47,7 +47,8 @@ pg_control_system(PG_FUNCTION_ARGS) LWLockRelease(ControlFileLock); if (!crc_ok) ereport(ERROR, - (errmsg("calculated CRC checksum does not match value stored in file"))); + (errcode(ERRCODE_DATA_CORRUPTED), + errmsg("calculated CRC checksum does not match value stored in file"))); values[0] = Int32GetDatum(ControlFile->pg_control_version); nulls[0] = false; @@ -87,7 +88,8 @@ pg_control_checkpoint(PG_FUNCTION_ARGS) LWLockRelease(ControlFileLock); if (!crc_ok) ereport(ERROR, - (errmsg("calculated CRC checksum does not match value stored in file"))); + (errcode(ERRCODE_DATA_CORRUPTED), + errmsg("calculated CRC checksum does not match value stored in file"))); /* * Calculate name of the WAL file containing the latest checkpoint's REDO @@ -184,7 +186,8 @@ pg_control_recovery(PG_FUNCTION_ARGS) LWLockRelease(ControlFileLock); if (!crc_ok) ereport(ERROR, - (errmsg("calculated CRC checksum does not match value stored in file"))); + (errcode(ERRCODE_DATA_CORRUPTED), + errmsg("calculated CRC checksum does not match value stored in file"))); values[0] = LSNGetDatum(ControlFile->minRecoveryPoint); nulls[0] = false; @@ -225,7 +228,8 @@ pg_control_init(PG_FUNCTION_ARGS) LWLockRelease(ControlFileLock); if (!crc_ok) ereport(ERROR, - (errmsg("calculated CRC checksum does not match value stored in file"))); + (errcode(ERRCODE_DATA_CORRUPTED), + errmsg("calculated CRC checksum does not match value stored in file"))); values[0] = Int32GetDatum(ControlFile->maxAlign); nulls[0] = false; diff --git a/src/test/regress/expected/tid.out b/src/test/regress/expected/tid.out index 45cc61fb1ca..d2dc23fbdeb 100644 --- a/src/test/regress/expected/tid.out +++ b/src/test/regress/expected/tid.out @@ -192,4 +192,12 @@ CREATE VIEW tid_view_fake_ctid AS SELECT 1 AS ctid, 2 AS a; SELECT currtid2('tid_view_fake_ctid'::text, '(0,1)'::tid); -- fails ERROR: ctid isn't of type TID DROP VIEW tid_view_fake_ctid; +-- ctid cannot be traced to a base relation +CREATE VIEW tid_view_grouped_ctid AS + SELECT ctid, a FROM tid_tab GROUP BY ctid, a; +\set VERBOSITY sqlstate +SELECT currtid2('tid_view_grouped_ctid'::text, '(0,1)'::tid); -- fails +ERROR: 0A000 +\set VERBOSITY default +DROP VIEW tid_view_grouped_ctid; DROP TABLE tid_tab CASCADE; diff --git a/src/test/regress/sql/tid.sql b/src/test/regress/sql/tid.sql index 51d00b92074..5176503951b 100644 --- a/src/test/regress/sql/tid.sql +++ b/src/test/regress/sql/tid.sql @@ -91,5 +91,12 @@ TRUNCATE tid_tab; CREATE VIEW tid_view_fake_ctid AS SELECT 1 AS ctid, 2 AS a; SELECT currtid2('tid_view_fake_ctid'::text, '(0,1)'::tid); -- fails DROP VIEW tid_view_fake_ctid; +-- ctid cannot be traced to a base relation +CREATE VIEW tid_view_grouped_ctid AS + SELECT ctid, a FROM tid_tab GROUP BY ctid, a; +\set VERBOSITY sqlstate +SELECT currtid2('tid_view_grouped_ctid'::text, '(0,1)'::tid); -- fails +\set VERBOSITY default +DROP VIEW tid_view_grouped_ctid; DROP TABLE tid_tab CASCADE; base-commit: 5624de9904c29224737574f039ba073bc02fba82 -- 2.34.1