From c5c4561cc4971a91b8460fe69ddb305d7a94d0a2 Mon Sep 17 00:00:00 2001
From: Jim Jones <jim.jones@uni-muenster.de>
Date: Sun, 18 Oct 2026 14:10:58 +0200
Subject: [PATCH v1 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 <jim.jones@uni-muenster.de>
Reported-by: Zsolt Parragi <zsolt.parragi@percona.com>
---
 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

