Hi Kirill On 25/10/2026 07:11, Kirill Reshke wrote: > Then on standby: > > reshke=# table u_toast; > ERROR: cannot access temporary or unlogged relations during recovery > reshke=# SELECT octet_length(t_attrs[1]) > FROM u_snapshot, > LATERAL heap_page_item_attrs(raw, 'u_toast'::regclass, true); > ERROR: could not open file "base/16384/16393": No such file or directory > CONTEXT: SQL function "heap_page_item_attrs" statement 1
Nice catch! I could reproduce the error and can confirm that your patch fixes it -- now merged into 0001. The remaining patches 0002 - 0004 remain unchanged. > > attached fixes an issue. > Also, Im +0.5 on not creating a TAP test for that -- too many cpu > cycles for too little benefit. Yeah, this is was my rationale as well. v2 attached. Thanks! Best, Jim
From 5ac944c873b6637c04e36f1ba1a5edcb8b347d1c Mon Sep 17 00:00:00 2001 From: Jim Jones <[email protected]> Date: Sun, 25 Oct 2026 11:06:06 +0100 Subject: [PATCH v2 1/4] pageinspect: Reject unlogged relations during recovery Unlogged tables and indexes have no data on a standby, so reading one there must fail. get_raw_page(), bt_metap(), bt_page_stats(), bt_multi_page_stats(), bt_page_items() and hash_bitmap_info() read the relation directly instead of going through the planner, so on a standby they failed with a confusing low-level message instead of the error that SELECT reports: ERROR: could not open file "base/5/16384": No such file or directory Check for this case and report the same error as SELECT: ERROR: cannot access temporary or unlogged relations during recovery The init fork of an unlogged relation does exist on a standby, so get_raw_page() can still read it. Author: Jim Jones <[email protected]> Co-Authored-by: Kirill Reshke <[email protected]> Reported-by: Zsolt Parragi <[email protected]> --- contrib/pageinspect/btreefuncs.c | 13 +++++++++++++ contrib/pageinspect/hashfuncs.c | 7 +++++++ contrib/pageinspect/heapfuncs.c | 10 ++++++++++ contrib/pageinspect/rawpage.c | 11 +++++++++++ 4 files changed, 41 insertions(+) diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c index 9917663593b..676afe51de8 100644 --- a/contrib/pageinspect/btreefuncs.c +++ b/contrib/pageinspect/btreefuncs.c @@ -30,6 +30,7 @@ #include "access/htup_details.h" #include "access/nbtree.h" #include "access/relation.h" +#include "access/xlog.h" #include "catalog/namespace.h" #include "catalog/pg_am.h" #include "catalog/pg_type.h" @@ -241,6 +242,12 @@ bt_index_block_validate(Relation rel, int64 blkno) (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot access temporary tables of other sessions"))); + /* Temporary and unlogged relations are inaccessible during recovery. */ + if (!RelationIsPermanent(rel) && RecoveryInProgress()) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot access temporary or unlogged relations during recovery"))); + if (blkno == 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -874,6 +881,12 @@ bt_metap(PG_FUNCTION_ARGS) (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot access temporary tables of other sessions"))); + /* Temporary and unlogged relations are inaccessible during recovery. */ + if (!RelationIsPermanent(rel) && RecoveryInProgress()) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot access temporary or unlogged relations during recovery"))); + buffer = ReadBuffer(rel, 0); LockBuffer(buffer, BUFFER_LOCK_SHARE); diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c index 30870329cc9..0f728d9add8 100644 --- a/contrib/pageinspect/hashfuncs.c +++ b/contrib/pageinspect/hashfuncs.c @@ -13,6 +13,7 @@ #include "access/hash.h" #include "access/htup_details.h" #include "access/relation.h" +#include "access/xlog.h" #include "catalog/pg_am.h" #include "catalog/pg_type.h" #include "funcapi.h" @@ -431,6 +432,12 @@ hash_bitmap_info(PG_FUNCTION_ARGS) (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot access temporary tables of other sessions"))); + /* Temporary and unlogged relations are inaccessible during recovery. */ + if (!RelationIsPermanent(indexRel) && RecoveryInProgress()) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot access temporary or unlogged relations during recovery"))); + if (ovflblkno < 0 || ovflblkno > MaxBlockNumber) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c index 7be4770dc84..57068eca2dd 100644 --- a/contrib/pageinspect/heapfuncs.c +++ b/contrib/pageinspect/heapfuncs.c @@ -27,6 +27,7 @@ #include "access/htup_details.h" #include "access/relation.h" +#include "access/xlog.h" #include "catalog/pg_am_d.h" #include "catalog/pg_type.h" #include "funcapi.h" @@ -389,7 +390,16 @@ tuple_data_split_internal(Oid relid, char *tupdata, errmsg("unexpected end of tuple data"))); if (attr->attlen == -1 && do_detoast) + { + /* A saved page can still refer to unlogged TOAST storage. */ + if (VARATT_IS_EXTERNAL_ONDISK(tupdata + off) && + !RelationIsPermanent(rel) && RecoveryInProgress()) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot access temporary or unlogged relations during recovery"))); + attr_data = pg_detoast_datum_copy((varlena *) (tupdata + off)); + } else { attr_data = (bytea *) palloc(len + VARHDRSZ); diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c index d136593edb2..05ecde3c20f 100644 --- a/contrib/pageinspect/rawpage.c +++ b/contrib/pageinspect/rawpage.c @@ -17,6 +17,7 @@ #include "access/htup_details.h" #include "access/relation.h" +#include "access/xlog.h" #include "catalog/namespace.h" #include "catalog/pg_type.h" #include "funcapi.h" @@ -175,6 +176,16 @@ get_raw_page_internal(text *relname, ForkNumber forknum, BlockNumber blkno) (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot access temporary tables of other sessions"))); + /* + * Temporary and unlogged relations are inaccessible during recovery, + * except for the init fork of an unlogged relation, which does exist. + */ + if (!RelationIsPermanent(rel) && RecoveryInProgress() && + forknum != INIT_FORKNUM) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot access temporary or unlogged relations during recovery"))); + if (blkno >= RelationGetNumberOfBlocksInFork(rel, forknum)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), -- 2.56.0
From 8bdc4a97aca4b1b9c8d8ce46777b8b5d4c8bee61 Mon Sep 17 00:00:00 2001 From: Jim Jones <[email protected]> Date: Sun, 18 Oct 2026 14:07:37 +0200 Subject: [PATCH v2 2/4] pgrowlocks: Reject unlogged tables during recovery Unlogged tables have no data on a standby, so reading one there must fail. pgrowlocks() reads the table directly instead of going through the planner, so on a standby it failed with a confusing low-level message instead of the error that SELECT reports: ERROR: could not open file "base/5/16384": No such file or directory Check for this case and report the same error as SELECT: ERROR: cannot access temporary or unlogged relations during recovery Author: Jim Jones <[email protected]> Reported-by: Zsolt Parragi <[email protected]> --- contrib/pgrowlocks/pgrowlocks.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/contrib/pgrowlocks/pgrowlocks.c b/contrib/pgrowlocks/pgrowlocks.c index 87bbde59937..84017271e98 100644 --- a/contrib/pgrowlocks/pgrowlocks.c +++ b/contrib/pgrowlocks/pgrowlocks.c @@ -29,6 +29,7 @@ #include "access/relscan.h" #include "access/tableam.h" #include "access/xact.h" +#include "access/xlog.h" #include "catalog/namespace.h" #include "catalog/pg_am_d.h" #include "catalog/pg_authid.h" @@ -114,6 +115,12 @@ pgrowlocks(PG_FUNCTION_ARGS) aclcheck_error(aclresult, get_relkind_objtype(rel->rd_rel->relkind), RelationGetRelationName(rel)); + /* Temporary and unlogged relations are inaccessible during recovery. */ + if (!RelationIsPermanent(rel) && RecoveryInProgress()) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot access temporary or unlogged relations during recovery"))); + /* Scan the relation */ scan = table_beginscan(rel, GetActiveSnapshot(), 0, NULL, SO_NONE); hscan = (HeapScanDesc) scan; -- 2.56.0
From 51fdf3cf462e5a2e11b6b07aac69bc9723681fbc Mon Sep 17 00:00:00 2001 From: Jim Jones <[email protected]> Date: Sun, 18 Oct 2026 14:09:33 +0200 Subject: [PATCH v2 3/4] pgstattuple: Reject unlogged relations during recovery Unlogged tables and indexes have no data on a standby, so reading one there must fail. pgstattuple(), pgstattuple_approx(), pg_relpages(), pgstatindex(), pgstatginindex() and pgstathashindex() read the relation directly instead of going through the planner, so on a standby they failed with a confusing low-level message instead of the error that SELECT reports: ERROR: could not open file "base/5/16384": No such file or directory Check for this case and report the same error as SELECT: ERROR: cannot access temporary or unlogged relations during recovery Author: Jim Jones <[email protected]> Reported-by: Zsolt Parragi <[email protected]> --- contrib/pgstattuple/pgstatapprox.c | 7 +++++++ contrib/pgstattuple/pgstatindex.c | 25 +++++++++++++++++++++++++ contrib/pgstattuple/pgstattuple.c | 7 +++++++ 3 files changed, 39 insertions(+) diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c index 21e0b50fb4b..38b0cc951e2 100644 --- a/contrib/pgstattuple/pgstatapprox.c +++ b/contrib/pgstattuple/pgstatapprox.c @@ -16,6 +16,7 @@ #include "access/htup_details.h" #include "access/relation.h" #include "access/visibilitymap.h" +#include "access/xlog.h" #include "catalog/pg_am_d.h" #include "commands/vacuum.h" #include "funcapi.h" @@ -332,6 +333,12 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo) (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot access temporary tables of other sessions"))); + /* Temporary and unlogged relations are inaccessible during recovery. */ + if (!RelationIsPermanent(rel) && RecoveryInProgress()) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot access temporary or unlogged relations during recovery"))); + /* * We support only relation kinds with a visibility map and a free space * map. diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c index 8951ad0aac4..87e79527361 100644 --- a/contrib/pgstattuple/pgstatindex.c +++ b/contrib/pgstattuple/pgstatindex.c @@ -32,6 +32,7 @@ #include "access/htup_details.h" #include "access/nbtree.h" #include "access/relation.h" +#include "access/xlog.h" #include "catalog/namespace.h" #include "catalog/pg_am.h" #include "funcapi.h" @@ -238,6 +239,12 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo) (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot access temporary tables of other sessions"))); + /* Temporary and unlogged relations are inaccessible during recovery. */ + if (!RelationIsPermanent(rel) && RecoveryInProgress()) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot access temporary or unlogged relations during recovery"))); + /* * A !indisready index could lead to ERRCODE_DATA_CORRUPTED later, so exit * early. We're capable of assessing an indisready&&!indisvalid index, @@ -482,6 +489,12 @@ pg_relpages_impl(Relation rel) RelationGetRelationName(rel)), errdetail_relkind_not_supported(rel->rd_rel->relkind))); + /* Temporary and unlogged relations are inaccessible during recovery. */ + if (!RelationIsPermanent(rel) && RecoveryInProgress()) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot access temporary or unlogged relations during recovery"))); + /* note: this will work OK on non-local temp tables */ relpages = RelationGetNumberOfBlocks(rel); @@ -557,6 +570,12 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo) (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot access temporary indexes of other sessions"))); + /* Temporary and unlogged relations are inaccessible during recovery. */ + if (!RelationIsPermanent(rel) && RecoveryInProgress()) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot access temporary or unlogged relations during recovery"))); + /* see pgstatindex_impl */ if (!rel->rd_index->indisvalid) ereport(ERROR, @@ -647,6 +666,12 @@ pgstathashindex(PG_FUNCTION_ARGS) (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot access temporary indexes of other sessions"))); + /* Temporary and unlogged relations are inaccessible during recovery. */ + if (!RelationIsPermanent(rel) && RecoveryInProgress()) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot access temporary or unlogged relations during recovery"))); + /* see pgstatindex_impl */ if (!rel->rd_index->indisvalid) ereport(ERROR, diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c index 6a7f8cb4a7c..f9495390673 100644 --- a/contrib/pgstattuple/pgstattuple.c +++ b/contrib/pgstattuple/pgstattuple.c @@ -30,6 +30,7 @@ #include "access/nbtree.h" #include "access/relscan.h" #include "access/tableam.h" +#include "access/xlog.h" #include "catalog/namespace.h" #include "catalog/pg_am_d.h" #include "funcapi.h" @@ -254,6 +255,12 @@ pgstat_relation(Relation rel, FunctionCallInfo fcinfo) (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot access temporary tables of other sessions"))); + /* Temporary and unlogged relations are inaccessible during recovery. */ + if (!RelationIsPermanent(rel) && RecoveryInProgress()) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot access temporary or unlogged relations during recovery"))); + if (RELKIND_HAS_TABLE_AM(rel->rd_rel->relkind) || rel->rd_rel->relkind == RELKIND_SEQUENCE) { -- 2.56.0
From 9cad4e80df9658cfdd5ae62d9f630b2357ace611 Mon Sep 17 00:00:00 2001 From: Jim Jones <[email protected]> Date: Sun, 18 Oct 2026 14:10:58 +0200 Subject: [PATCH v2 4/4] pg_visibility: Reject unlogged tables during recovery Unlogged tables have no data on a standby, so reading one there must fail. pg_visibility(), pg_visibility_map(regclass), pg_check_frozen() and pg_check_visible() read the table directly instead of going through the planner, so on a standby they failed with a confusing low-level message instead of the error that SELECT reports: ERROR: could not open file "base/5/16384": No such file or directory Check for this case and report the same error as SELECT: ERROR: cannot access temporary or unlogged relations during recovery pg_visibility_map(regclass, bigint) and pg_visibility_map_summary() already return a result on a standby, so they are left unchanged. Author: Jim Jones <[email protected]> Reported-by: Zsolt Parragi <[email protected]> --- contrib/pg_visibility/pg_visibility.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c index 4292d077be1..054503319c6 100644 --- a/contrib/pg_visibility/pg_visibility.c +++ b/contrib/pg_visibility/pg_visibility.c @@ -13,6 +13,7 @@ #include "access/heapam.h" #include "access/htup_details.h" #include "access/visibilitymap.h" +#include "access/xlog.h" #include "access/xloginsert.h" #include "catalog/pg_type.h" #include "catalog/storage_xlog.h" @@ -138,6 +139,12 @@ pg_visibility(PG_FUNCTION_ARGS) /* Only some relkinds have a visibility map */ check_relation_relkind(rel); + /* Temporary and unlogged relations are inaccessible during recovery. */ + if (!RelationIsPermanent(rel) && RecoveryInProgress()) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot access temporary or unlogged relations during recovery"))); + if (blkno < 0 || blkno > MaxBlockNumber) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -497,6 +504,12 @@ collect_visibility_data(Oid relid, bool include_pd) /* Only some relkinds have a visibility map */ check_relation_relkind(rel); + /* Temporary and unlogged relations are inaccessible during recovery. */ + if (!RelationIsPermanent(rel) && RecoveryInProgress()) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot access temporary or unlogged relations during recovery"))); + nblocks = RelationGetNumberOfBlocks(rel); info = palloc0(offsetof(vbits, bits) + nblocks); info->next = 0; @@ -711,6 +724,12 @@ collect_corrupt_items(Oid relid, bool all_visible, bool all_frozen) /* Only some relkinds have a visibility map */ check_relation_relkind(rel); + /* Temporary and unlogged relations are inaccessible during recovery. */ + if (!RelationIsPermanent(rel) && RecoveryInProgress()) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot access temporary or unlogged relations during recovery"))); + if (all_visible) OldestXmin = GetStrictOldestNonRemovableTransactionId(rel); -- 2.56.0
