On Mon, Mar 28, 2022 at 05:09:10PM +0200, Matthias van de Meent wrote:
> Not all clusters have checksums enabled (boo!, but we can't
> realistically fix that), so on-disk corruption could reasonably
> propagate to the rest of such system. Additionally, checksums are only
> checked on read, and updated when the page is written to disk (in
> PageSetChecksumCopy called from FlushBuffer), but this does not check
> for signs of page corruption. As such, a memory bug resulting in
> in-memory corruption of pd_special would persist and would currently
> have the potential to further corrupt neighbouring buffers.

Well, if it comes to corruption then pd_special is not the only
problem, just one part of it.  A broken pd_lower or pd_lower or even
pd_lsn could also cause AMs to point at areas they should not.  There
are many reasons that could make things go wrong depending on the
compiled page size.

>>> A second reason would be less indirection to get to the opaque
>>> pointer. This should improve performance a bit in those cases where we
>>> (initially) only want to access the [Index]PageOpaque struct.
>>
>> We don't have many cases that do that, do we?
> 
> Indeed not many, but I know that at least the nbtree-code has some
> cases where it uses the opaque before other fields in the header are
> accessed (sometimes even without accessing the header for other
> reasons): in _bt_moveright and _bt_walk_left. There might be more; but
> these are cases I know of.

Even these are marginal as the page is already loaded in the shared
buffers..

While looking at the page, the pieces in 0002 and 0003 that I really
liked are the introduction of the macros to grab the special area for
btree and hash.  This brings the code of those APIs closer to GiST,
SpGiST and GIN.  And it is possible to move to a possible change in
the checks and/or the shape of all the *GetOpaque macros at once after
the switch to this part is done.  So I don't really mind introducing
this part.

PageGetSpecialOpaque() would not have saved the day with the recent
pageinspect changes, and that's just moving the responsability of the
page header to something else.  I am not sure if it is a good idea to
have a mention of the opaque page type in bufpage.h actually, as this
is optional.  Having an AssertMacro() checking that pd_special is in
line with MAXALIGN(sizeof(OpaqueData)) is attractive, but I'd rather
keep that in each AM's headers per its optional nature, and an index
AM may handle things differently depending on a page type, as well.
--
Michael
From e12d282461c9e4a1cba89cb7ea8e6dde90c829a6 Mon Sep 17 00:00:00 2001
From: Michael Paquier <mich...@paquier.xyz>
Date: Thu, 31 Mar 2022 16:30:52 +0900
Subject: [PATCH] Introduce macros for hash and btree to grab their opaque area

---
 src/include/access/hash.h               |  2 +
 src/include/access/nbtree.h             |  8 ++--
 src/backend/access/hash/hash.c          |  6 +--
 src/backend/access/hash/hash_xlog.c     | 26 +++++------
 src/backend/access/hash/hashinsert.c    |  6 +--
 src/backend/access/hash/hashovfl.c      | 22 +++++-----
 src/backend/access/hash/hashpage.c      | 30 ++++++-------
 src/backend/access/hash/hashsearch.c    | 12 ++---
 src/backend/access/hash/hashutil.c      |  4 +-
 src/backend/access/nbtree/nbtdedup.c    |  6 +--
 src/backend/access/nbtree/nbtinsert.c   | 46 ++++++++++----------
 src/backend/access/nbtree/nbtpage.c     | 58 ++++++++++++-------------
 src/backend/access/nbtree/nbtree.c      |  2 +-
 src/backend/access/nbtree/nbtsearch.c   | 34 +++++++--------
 src/backend/access/nbtree/nbtsort.c     | 12 ++---
 src/backend/access/nbtree/nbtsplitloc.c |  2 +-
 src/backend/access/nbtree/nbtutils.c    |  6 +--
 src/backend/access/nbtree/nbtxlog.c     | 34 +++++++--------
 contrib/amcheck/verify_nbtree.c         | 32 +++++++-------
 contrib/pageinspect/btreefuncs.c        |  6 +--
 contrib/pageinspect/hashfuncs.c         |  6 +--
 contrib/pgstattuple/pgstatindex.c       |  4 +-
 contrib/pgstattuple/pgstattuple.c       |  4 +-
 23 files changed, 186 insertions(+), 182 deletions(-)

diff --git a/src/include/access/hash.h b/src/include/access/hash.h
index cd7b2a53d8..a22e328762 100644
--- a/src/include/access/hash.h
+++ b/src/include/access/hash.h
@@ -85,6 +85,8 @@ typedef struct HashPageOpaqueData
 
 typedef HashPageOpaqueData *HashPageOpaque;
 
+#define HashPageGetOpaque(page) ( (HashPageOpaque) PageGetSpecialPointer(page) )
+
 #define H_NEEDS_SPLIT_CLEANUP(opaque)	(((opaque)->hasho_flag & LH_BUCKET_NEEDS_SPLIT_CLEANUP) != 0)
 #define H_BUCKET_BEING_SPLIT(opaque)	(((opaque)->hasho_flag & LH_BUCKET_BEING_SPLIT) != 0)
 #define H_BUCKET_BEING_POPULATED(opaque)	(((opaque)->hasho_flag & LH_BUCKET_BEING_POPULATED) != 0)
diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h
index 9fec6fb1a8..5625a90922 100644
--- a/src/include/access/nbtree.h
+++ b/src/include/access/nbtree.h
@@ -70,6 +70,8 @@ typedef struct BTPageOpaqueData
 
 typedef BTPageOpaqueData *BTPageOpaque;
 
+#define BTPageGetOpaque(page) ( (BTPageOpaque) PageGetSpecialPointer(page) )
+
 /* Bits defined in btpo_flags */
 #define BTP_LEAF		(1 << 0)	/* leaf page, i.e. not internal page */
 #define BTP_ROOT		(1 << 1)	/* root page (has no parent) */
@@ -241,7 +243,7 @@ BTPageSetDeleted(Page page, FullTransactionId safexid)
 	PageHeader	header;
 	BTDeletedPageData *contents;
 
-	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	opaque = BTPageGetOpaque(page);
 	header = ((PageHeader) page);
 
 	opaque->btpo_flags &= ~BTP_HALF_DEAD;
@@ -263,7 +265,7 @@ BTPageGetDeleteXid(Page page)
 
 	/* We only expect to be called with a deleted page */
 	Assert(!PageIsNew(page));
-	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	opaque = BTPageGetOpaque(page);
 	Assert(P_ISDELETED(opaque));
 
 	/* pg_upgrade'd deleted page -- must be safe to delete now */
@@ -294,7 +296,7 @@ BTPageIsRecyclable(Page page)
 	Assert(!PageIsNew(page));
 
 	/* Recycling okay iff page is deleted and safexid is old enough */
-	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	opaque = BTPageGetOpaque(page);
 	if (P_ISDELETED(opaque))
 	{
 		/*
diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c
index a259a301fa..fd1a7119b6 100644
--- a/src/backend/access/hash/hash.c
+++ b/src/backend/access/hash/hash.c
@@ -515,7 +515,7 @@ loop_top:
 		_hash_checkpage(rel, buf, LH_BUCKET_PAGE);
 
 		page = BufferGetPage(buf);
-		bucket_opaque = (HashPageOpaque) PageGetSpecialPointer(page);
+		bucket_opaque = HashPageGetOpaque(page);
 
 		/*
 		 * If the bucket contains tuples that are moved by split, then we need
@@ -717,7 +717,7 @@ hashbucketcleanup(Relation rel, Bucket cur_bucket, Buffer bucket_buf,
 		vacuum_delay_point();
 
 		page = BufferGetPage(buf);
-		opaque = (HashPageOpaque) PageGetSpecialPointer(page);
+		opaque = HashPageGetOpaque(page);
 
 		/* Scan each tuple in page */
 		maxoffno = PageGetMaxOffsetNumber(page);
@@ -884,7 +884,7 @@ hashbucketcleanup(Relation rel, Bucket cur_bucket, Buffer bucket_buf,
 		Page		page;
 
 		page = BufferGetPage(bucket_buf);
-		bucket_opaque = (HashPageOpaque) PageGetSpecialPointer(page);
+		bucket_opaque = HashPageGetOpaque(page);
 
 		/* No ereport(ERROR) until changes are logged */
 		START_CRIT_SECTION();
diff --git a/src/backend/access/hash/hash_xlog.c b/src/backend/access/hash/hash_xlog.c
index 55937b9a68..62dbfc3a5d 100644
--- a/src/backend/access/hash/hash_xlog.c
+++ b/src/backend/access/hash/hash_xlog.c
@@ -203,7 +203,7 @@ hash_xlog_add_ovfl_page(XLogReaderState *record)
 				  true);
 	/* update backlink */
 	ovflpage = BufferGetPage(ovflbuf);
-	ovflopaque = (HashPageOpaque) PageGetSpecialPointer(ovflpage);
+	ovflopaque = HashPageGetOpaque(ovflpage);
 	ovflopaque->hasho_prevblkno = leftblk;
 
 	PageSetLSN(ovflpage, lsn);
@@ -215,7 +215,7 @@ hash_xlog_add_ovfl_page(XLogReaderState *record)
 		HashPageOpaque leftopaque;
 
 		leftpage = BufferGetPage(leftbuf);
-		leftopaque = (HashPageOpaque) PageGetSpecialPointer(leftpage);
+		leftopaque = HashPageGetOpaque(leftpage);
 		leftopaque->hasho_nextblkno = rightblk;
 
 		PageSetLSN(leftpage, lsn);
@@ -342,7 +342,7 @@ hash_xlog_split_allocate_page(XLogReaderState *record)
 		HashPageOpaque oldopaque;
 
 		oldpage = BufferGetPage(oldbuf);
-		oldopaque = (HashPageOpaque) PageGetSpecialPointer(oldpage);
+		oldopaque = HashPageGetOpaque(oldpage);
 
 		oldopaque->hasho_flag = xlrec->old_bucket_flag;
 		oldopaque->hasho_prevblkno = xlrec->new_bucket;
@@ -465,7 +465,7 @@ hash_xlog_split_complete(XLogReaderState *record)
 		HashPageOpaque oldopaque;
 
 		oldpage = BufferGetPage(oldbuf);
-		oldopaque = (HashPageOpaque) PageGetSpecialPointer(oldpage);
+		oldopaque = HashPageGetOpaque(oldpage);
 
 		oldopaque->hasho_flag = xlrec->old_bucket_flag;
 
@@ -488,7 +488,7 @@ hash_xlog_split_complete(XLogReaderState *record)
 		HashPageOpaque nopaque;
 
 		newpage = BufferGetPage(newbuf);
-		nopaque = (HashPageOpaque) PageGetSpecialPointer(newpage);
+		nopaque = HashPageGetOpaque(newpage);
 
 		nopaque->hasho_flag = xlrec->new_bucket_flag;
 
@@ -710,7 +710,7 @@ hash_xlog_squeeze_page(XLogReaderState *record)
 		 */
 		if (xldata->is_prev_bucket_same_wrt)
 		{
-			HashPageOpaque writeopaque = (HashPageOpaque) PageGetSpecialPointer(writepage);
+			HashPageOpaque writeopaque = HashPageGetOpaque(writepage);
 
 			writeopaque->hasho_nextblkno = xldata->nextblkno;
 		}
@@ -729,7 +729,7 @@ hash_xlog_squeeze_page(XLogReaderState *record)
 
 		_hash_pageinit(ovflpage, BufferGetPageSize(ovflbuf));
 
-		ovflopaque = (HashPageOpaque) PageGetSpecialPointer(ovflpage);
+		ovflopaque = HashPageGetOpaque(ovflpage);
 
 		ovflopaque->hasho_prevblkno = InvalidBlockNumber;
 		ovflopaque->hasho_nextblkno = InvalidBlockNumber;
@@ -748,7 +748,7 @@ hash_xlog_squeeze_page(XLogReaderState *record)
 		XLogReadBufferForRedo(record, 3, &prevbuf) == BLK_NEEDS_REDO)
 	{
 		Page		prevpage = BufferGetPage(prevbuf);
-		HashPageOpaque prevopaque = (HashPageOpaque) PageGetSpecialPointer(prevpage);
+		HashPageOpaque prevopaque = HashPageGetOpaque(prevpage);
 
 		prevopaque->hasho_nextblkno = xldata->nextblkno;
 
@@ -766,7 +766,7 @@ hash_xlog_squeeze_page(XLogReaderState *record)
 		if (XLogReadBufferForRedo(record, 4, &nextbuf) == BLK_NEEDS_REDO)
 		{
 			Page		nextpage = BufferGetPage(nextbuf);
-			HashPageOpaque nextopaque = (HashPageOpaque) PageGetSpecialPointer(nextpage);
+			HashPageOpaque nextopaque = HashPageGetOpaque(nextpage);
 
 			nextopaque->hasho_prevblkno = xldata->prevblkno;
 
@@ -903,7 +903,7 @@ hash_xlog_delete(XLogReaderState *record)
 		{
 			HashPageOpaque pageopaque;
 
-			pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
+			pageopaque = HashPageGetOpaque(page);
 			pageopaque->hasho_flag &= ~LH_PAGE_HAS_DEAD_TUPLES;
 		}
 
@@ -933,7 +933,7 @@ hash_xlog_split_cleanup(XLogReaderState *record)
 
 		page = (Page) BufferGetPage(buffer);
 
-		bucket_opaque = (HashPageOpaque) PageGetSpecialPointer(page);
+		bucket_opaque = HashPageGetOpaque(page);
 		bucket_opaque->hasho_flag &= ~LH_BUCKET_NEEDS_SPLIT_CLEANUP;
 		PageSetLSN(page, lsn);
 		MarkBufferDirty(buffer);
@@ -1024,7 +1024,7 @@ hash_xlog_vacuum_one_page(XLogReaderState *record)
 		 * Mark the page as not containing any LP_DEAD items. See comments in
 		 * _hash_vacuum_one_page() for details.
 		 */
-		pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
+		pageopaque = HashPageGetOpaque(page);
 		pageopaque->hasho_flag &= ~LH_PAGE_HAS_DEAD_TUPLES;
 
 		PageSetLSN(page, lsn);
@@ -1116,7 +1116,7 @@ hash_mask(char *pagedata, BlockNumber blkno)
 	mask_page_hint_bits(page);
 	mask_unused_space(page);
 
-	opaque = (HashPageOpaque) PageGetSpecialPointer(page);
+	opaque = HashPageGetOpaque(page);
 
 	pagetype = opaque->hasho_flag & LH_PAGE_TYPE;
 	if (pagetype == LH_UNUSED_PAGE)
diff --git a/src/backend/access/hash/hashinsert.c b/src/backend/access/hash/hashinsert.c
index faf609c157..4f2fecb908 100644
--- a/src/backend/access/hash/hashinsert.c
+++ b/src/backend/access/hash/hashinsert.c
@@ -95,7 +95,7 @@ restart_insert:
 	bucket_buf = buf;
 
 	page = BufferGetPage(buf);
-	pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
+	pageopaque = HashPageGetOpaque(page);
 	bucket = pageopaque->hasho_bucket;
 
 	/*
@@ -183,7 +183,7 @@ restart_insert:
 			/* should fit now, given test above */
 			Assert(PageGetFreeSpace(page) >= itemsz);
 		}
-		pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
+		pageopaque = HashPageGetOpaque(page);
 		Assert((pageopaque->hasho_flag & LH_PAGE_TYPE) == LH_OVERFLOW_PAGE);
 		Assert(pageopaque->hasho_bucket == bucket);
 	}
@@ -384,7 +384,7 @@ _hash_vacuum_one_page(Relation rel, Relation hrel, Buffer metabuf, Buffer buf)
 		 * check it. Remember that LH_PAGE_HAS_DEAD_TUPLES is only a hint
 		 * anyway.
 		 */
-		pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
+		pageopaque = HashPageGetOpaque(page);
 		pageopaque->hasho_flag &= ~LH_PAGE_HAS_DEAD_TUPLES;
 
 		metap = HashPageGetMeta(BufferGetPage(metabuf));
diff --git a/src/backend/access/hash/hashovfl.c b/src/backend/access/hash/hashovfl.c
index 4836875196..e34cfc302d 100644
--- a/src/backend/access/hash/hashovfl.c
+++ b/src/backend/access/hash/hashovfl.c
@@ -159,7 +159,7 @@ _hash_addovflpage(Relation rel, Buffer metabuf, Buffer buf, bool retain_pin)
 		BlockNumber nextblkno;
 
 		page = BufferGetPage(buf);
-		pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
+		pageopaque = HashPageGetOpaque(page);
 		nextblkno = pageopaque->hasho_nextblkno;
 
 		if (!BlockNumberIsValid(nextblkno))
@@ -364,7 +364,7 @@ found:
 
 	/* initialize new overflow page */
 	ovflpage = BufferGetPage(ovflbuf);
-	ovflopaque = (HashPageOpaque) PageGetSpecialPointer(ovflpage);
+	ovflopaque = HashPageGetOpaque(ovflpage);
 	ovflopaque->hasho_prevblkno = BufferGetBlockNumber(buf);
 	ovflopaque->hasho_nextblkno = InvalidBlockNumber;
 	ovflopaque->hasho_bucket = pageopaque->hasho_bucket;
@@ -516,7 +516,7 @@ _hash_freeovflpage(Relation rel, Buffer bucketbuf, Buffer ovflbuf,
 	_hash_checkpage(rel, ovflbuf, LH_OVERFLOW_PAGE);
 	ovflblkno = BufferGetBlockNumber(ovflbuf);
 	ovflpage = BufferGetPage(ovflbuf);
-	ovflopaque = (HashPageOpaque) PageGetSpecialPointer(ovflpage);
+	ovflopaque = HashPageGetOpaque(ovflpage);
 	nextblkno = ovflopaque->hasho_nextblkno;
 	prevblkno = ovflopaque->hasho_prevblkno;
 	writeblkno = BufferGetBlockNumber(wbuf);
@@ -600,7 +600,7 @@ _hash_freeovflpage(Relation rel, Buffer bucketbuf, Buffer ovflbuf,
 	 */
 	_hash_pageinit(ovflpage, BufferGetPageSize(ovflbuf));
 
-	ovflopaque = (HashPageOpaque) PageGetSpecialPointer(ovflpage);
+	ovflopaque = HashPageGetOpaque(ovflpage);
 
 	ovflopaque->hasho_prevblkno = InvalidBlockNumber;
 	ovflopaque->hasho_nextblkno = InvalidBlockNumber;
@@ -613,7 +613,7 @@ _hash_freeovflpage(Relation rel, Buffer bucketbuf, Buffer ovflbuf,
 	if (BufferIsValid(prevbuf))
 	{
 		Page		prevpage = BufferGetPage(prevbuf);
-		HashPageOpaque prevopaque = (HashPageOpaque) PageGetSpecialPointer(prevpage);
+		HashPageOpaque prevopaque = HashPageGetOpaque(prevpage);
 
 		Assert(prevopaque->hasho_bucket == bucket);
 		prevopaque->hasho_nextblkno = nextblkno;
@@ -622,7 +622,7 @@ _hash_freeovflpage(Relation rel, Buffer bucketbuf, Buffer ovflbuf,
 	if (BufferIsValid(nextbuf))
 	{
 		Page		nextpage = BufferGetPage(nextbuf);
-		HashPageOpaque nextopaque = (HashPageOpaque) PageGetSpecialPointer(nextpage);
+		HashPageOpaque nextopaque = HashPageGetOpaque(nextpage);
 
 		Assert(nextopaque->hasho_bucket == bucket);
 		nextopaque->hasho_prevblkno = prevblkno;
@@ -751,7 +751,7 @@ _hash_initbitmapbuffer(Buffer buf, uint16 bmsize, bool initpage)
 		_hash_pageinit(pg, BufferGetPageSize(buf));
 
 	/* initialize the page's special space */
-	op = (HashPageOpaque) PageGetSpecialPointer(pg);
+	op = HashPageGetOpaque(pg);
 	op->hasho_prevblkno = InvalidBlockNumber;
 	op->hasho_nextblkno = InvalidBlockNumber;
 	op->hasho_bucket = InvalidBucket;
@@ -824,7 +824,7 @@ _hash_squeezebucket(Relation rel,
 	wblkno = bucket_blkno;
 	wbuf = bucket_buf;
 	wpage = BufferGetPage(wbuf);
-	wopaque = (HashPageOpaque) PageGetSpecialPointer(wpage);
+	wopaque = HashPageGetOpaque(wpage);
 
 	/*
 	 * if there aren't any overflow pages, there's nothing to squeeze. caller
@@ -855,7 +855,7 @@ _hash_squeezebucket(Relation rel,
 										  LH_OVERFLOW_PAGE,
 										  bstrategy);
 		rpage = BufferGetPage(rbuf);
-		ropaque = (HashPageOpaque) PageGetSpecialPointer(rpage);
+		ropaque = HashPageGetOpaque(rpage);
 		Assert(ropaque->hasho_bucket == bucket);
 	} while (BlockNumberIsValid(ropaque->hasho_nextblkno));
 
@@ -1005,7 +1005,7 @@ readpage:
 
 				wbuf = next_wbuf;
 				wpage = BufferGetPage(wbuf);
-				wopaque = (HashPageOpaque) PageGetSpecialPointer(wpage);
+				wopaque = HashPageGetOpaque(wpage);
 				Assert(wopaque->hasho_bucket == bucket);
 				retain_pin = false;
 
@@ -1076,7 +1076,7 @@ readpage:
 										  LH_OVERFLOW_PAGE,
 										  bstrategy);
 		rpage = BufferGetPage(rbuf);
-		ropaque = (HashPageOpaque) PageGetSpecialPointer(rpage);
+		ropaque = HashPageGetOpaque(rpage);
 		Assert(ropaque->hasho_bucket == bucket);
 	}
 
diff --git a/src/backend/access/hash/hashpage.c b/src/backend/access/hash/hashpage.c
index 28c5297a1d..39206d1942 100644
--- a/src/backend/access/hash/hashpage.c
+++ b/src/backend/access/hash/hashpage.c
@@ -166,7 +166,7 @@ _hash_initbuf(Buffer buf, uint32 max_bucket, uint32 num_bucket, uint32 flag,
 	if (initpage)
 		_hash_pageinit(page, BufferGetPageSize(buf));
 
-	pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
+	pageopaque = HashPageGetOpaque(page);
 
 	/*
 	 * Set hasho_prevblkno with current hashm_maxbucket. This value will be
@@ -529,7 +529,7 @@ _hash_init_metabuffer(Buffer buf, double num_tuples, RegProcedure procid,
 	if (initpage)
 		_hash_pageinit(page, BufferGetPageSize(buf));
 
-	pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
+	pageopaque = HashPageGetOpaque(page);
 	pageopaque->hasho_prevblkno = InvalidBlockNumber;
 	pageopaque->hasho_nextblkno = InvalidBlockNumber;
 	pageopaque->hasho_bucket = InvalidBucket;
@@ -693,7 +693,7 @@ restart_expand:
 		goto fail;
 
 	opage = BufferGetPage(buf_oblkno);
-	oopaque = (HashPageOpaque) PageGetSpecialPointer(opage);
+	oopaque = HashPageGetOpaque(opage);
 
 	/*
 	 * We want to finish the split from a bucket as there is no apparent
@@ -864,7 +864,7 @@ restart_expand:
 	lowmask = metap->hashm_lowmask;
 
 	opage = BufferGetPage(buf_oblkno);
-	oopaque = (HashPageOpaque) PageGetSpecialPointer(opage);
+	oopaque = HashPageGetOpaque(opage);
 
 	/*
 	 * Mark the old bucket to indicate that split is in progress.  (At
@@ -883,7 +883,7 @@ restart_expand:
 	 * initialize the new bucket's primary page and mark it to indicate that
 	 * split is in progress.
 	 */
-	nopaque = (HashPageOpaque) PageGetSpecialPointer(npage);
+	nopaque = HashPageGetOpaque(npage);
 	nopaque->hasho_prevblkno = maxbucket;
 	nopaque->hasho_nextblkno = InvalidBlockNumber;
 	nopaque->hasho_bucket = new_bucket;
@@ -1010,7 +1010,7 @@ _hash_alloc_buckets(Relation rel, BlockNumber firstblock, uint32 nblocks)
 	 */
 	_hash_pageinit(page, BLCKSZ);
 
-	ovflopaque = (HashPageOpaque) PageGetSpecialPointer(page);
+	ovflopaque = HashPageGetOpaque(page);
 
 	ovflopaque->hasho_prevblkno = InvalidBlockNumber;
 	ovflopaque->hasho_nextblkno = InvalidBlockNumber;
@@ -1091,11 +1091,11 @@ _hash_splitbucket(Relation rel,
 
 	bucket_obuf = obuf;
 	opage = BufferGetPage(obuf);
-	oopaque = (HashPageOpaque) PageGetSpecialPointer(opage);
+	oopaque = HashPageGetOpaque(opage);
 
 	bucket_nbuf = nbuf;
 	npage = BufferGetPage(nbuf);
-	nopaque = (HashPageOpaque) PageGetSpecialPointer(npage);
+	nopaque = HashPageGetOpaque(npage);
 
 	/* Copy the predicate locks from old bucket to new bucket. */
 	PredicateLockPageSplit(rel,
@@ -1198,7 +1198,7 @@ _hash_splitbucket(Relation rel,
 					/* chain to a new overflow page */
 					nbuf = _hash_addovflpage(rel, metabuf, nbuf, (nbuf == bucket_nbuf));
 					npage = BufferGetPage(nbuf);
-					nopaque = (HashPageOpaque) PageGetSpecialPointer(npage);
+					nopaque = HashPageGetOpaque(npage);
 				}
 
 				itups[nitups++] = new_itup;
@@ -1251,7 +1251,7 @@ _hash_splitbucket(Relation rel,
 		/* Else, advance to next old page */
 		obuf = _hash_getbuf(rel, oblkno, HASH_READ, LH_OVERFLOW_PAGE);
 		opage = BufferGetPage(obuf);
-		oopaque = (HashPageOpaque) PageGetSpecialPointer(opage);
+		oopaque = HashPageGetOpaque(opage);
 	}
 
 	/*
@@ -1264,11 +1264,11 @@ _hash_splitbucket(Relation rel,
 	 */
 	LockBuffer(bucket_obuf, BUFFER_LOCK_EXCLUSIVE);
 	opage = BufferGetPage(bucket_obuf);
-	oopaque = (HashPageOpaque) PageGetSpecialPointer(opage);
+	oopaque = HashPageGetOpaque(opage);
 
 	LockBuffer(bucket_nbuf, BUFFER_LOCK_EXCLUSIVE);
 	npage = BufferGetPage(bucket_nbuf);
-	nopaque = (HashPageOpaque) PageGetSpecialPointer(npage);
+	nopaque = HashPageGetOpaque(npage);
 
 	START_CRIT_SECTION();
 
@@ -1392,7 +1392,7 @@ _hash_finish_split(Relation rel, Buffer metabuf, Buffer obuf, Bucket obucket,
 			bucket_nbuf = nbuf;
 
 		npage = BufferGetPage(nbuf);
-		npageopaque = (HashPageOpaque) PageGetSpecialPointer(npage);
+		npageopaque = HashPageGetOpaque(npage);
 
 		/* Scan each tuple in new page */
 		nmaxoffnum = PageGetMaxOffsetNumber(npage);
@@ -1446,7 +1446,7 @@ _hash_finish_split(Relation rel, Buffer metabuf, Buffer obuf, Bucket obucket,
 	}
 
 	npage = BufferGetPage(bucket_nbuf);
-	npageopaque = (HashPageOpaque) PageGetSpecialPointer(npage);
+	npageopaque = HashPageGetOpaque(npage);
 	nbucket = npageopaque->hasho_bucket;
 
 	_hash_splitbucket(rel, metabuf, obucket,
@@ -1587,7 +1587,7 @@ _hash_getbucketbuf_from_hashkey(Relation rel, uint32 hashkey, int access,
 		/* Fetch the primary bucket page for the bucket */
 		buf = _hash_getbuf(rel, blkno, access, LH_BUCKET_PAGE);
 		page = BufferGetPage(buf);
-		opaque = (HashPageOpaque) PageGetSpecialPointer(page);
+		opaque = HashPageGetOpaque(page);
 		Assert(opaque->hasho_bucket == bucket);
 		Assert(opaque->hasho_prevblkno != InvalidBlockNumber);
 
diff --git a/src/backend/access/hash/hashsearch.c b/src/backend/access/hash/hashsearch.c
index 7ca542a3fb..524af27409 100644
--- a/src/backend/access/hash/hashsearch.c
+++ b/src/backend/access/hash/hashsearch.c
@@ -187,7 +187,7 @@ _hash_readnext(IndexScanDesc scan,
 	{
 		*pagep = BufferGetPage(*bufp);
 		TestForOldSnapshot(scan->xs_snapshot, rel, *pagep);
-		*opaquep = (HashPageOpaque) PageGetSpecialPointer(*pagep);
+		*opaquep = HashPageGetOpaque(*pagep);
 	}
 }
 
@@ -233,7 +233,7 @@ _hash_readprev(IndexScanDesc scan,
 							 LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
 		*pagep = BufferGetPage(*bufp);
 		TestForOldSnapshot(scan->xs_snapshot, rel, *pagep);
-		*opaquep = (HashPageOpaque) PageGetSpecialPointer(*pagep);
+		*opaquep = HashPageGetOpaque(*pagep);
 
 		/*
 		 * We always maintain the pin on bucket page for whole scan operation,
@@ -258,7 +258,7 @@ _hash_readprev(IndexScanDesc scan,
 
 		LockBuffer(*bufp, BUFFER_LOCK_SHARE);
 		*pagep = BufferGetPage(*bufp);
-		*opaquep = (HashPageOpaque) PageGetSpecialPointer(*pagep);
+		*opaquep = HashPageGetOpaque(*pagep);
 
 		/* move to the end of bucket chain */
 		while (BlockNumberIsValid((*opaquep)->hasho_nextblkno))
@@ -352,7 +352,7 @@ _hash_first(IndexScanDesc scan, ScanDirection dir)
 	PredicateLockPage(rel, BufferGetBlockNumber(buf), scan->xs_snapshot);
 	page = BufferGetPage(buf);
 	TestForOldSnapshot(scan->xs_snapshot, rel, page);
-	opaque = (HashPageOpaque) PageGetSpecialPointer(page);
+	opaque = HashPageGetOpaque(page);
 	bucket = opaque->hasho_bucket;
 
 	so->hashso_bucket_buf = buf;
@@ -398,7 +398,7 @@ _hash_first(IndexScanDesc scan, ScanDirection dir)
 
 		LockBuffer(buf, BUFFER_LOCK_SHARE);
 		page = BufferGetPage(buf);
-		opaque = (HashPageOpaque) PageGetSpecialPointer(page);
+		opaque = HashPageGetOpaque(page);
 		Assert(opaque->hasho_bucket == bucket);
 
 		if (H_BUCKET_BEING_POPULATED(opaque))
@@ -463,7 +463,7 @@ _hash_readpage(IndexScanDesc scan, Buffer *bufP, ScanDirection dir)
 	Assert(BufferIsValid(buf));
 	_hash_checkpage(rel, buf, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
 	page = BufferGetPage(buf);
-	opaque = (HashPageOpaque) PageGetSpecialPointer(page);
+	opaque = HashPageGetOpaque(page);
 
 	so->currPos.buf = buf;
 	so->currPos.currPage = BufferGetBlockNumber(buf);
diff --git a/src/backend/access/hash/hashutil.c b/src/backend/access/hash/hashutil.c
index edb6fa968f..fe37bc47cb 100644
--- a/src/backend/access/hash/hashutil.c
+++ b/src/backend/access/hash/hashutil.c
@@ -239,7 +239,7 @@ _hash_checkpage(Relation rel, Buffer buf, int flags)
 
 	if (flags)
 	{
-		HashPageOpaque opaque = (HashPageOpaque) PageGetSpecialPointer(page);
+		HashPageOpaque opaque = HashPageGetOpaque(page);
 
 		if ((opaque->hasho_flag & flags) == 0)
 			ereport(ERROR,
@@ -574,7 +574,7 @@ _hash_kill_items(IndexScanDesc scan)
 		buf = _hash_getbuf(rel, blkno, HASH_READ, LH_OVERFLOW_PAGE);
 
 	page = BufferGetPage(buf);
-	opaque = (HashPageOpaque) PageGetSpecialPointer(page);
+	opaque = HashPageGetOpaque(page);
 	maxoff = PageGetMaxOffsetNumber(page);
 
 	for (i = 0; i < numKilled; i++)
diff --git a/src/backend/access/nbtree/nbtdedup.c b/src/backend/access/nbtree/nbtdedup.c
index 4c48554aec..3e11805293 100644
--- a/src/backend/access/nbtree/nbtdedup.c
+++ b/src/backend/access/nbtree/nbtdedup.c
@@ -62,7 +62,7 @@ _bt_dedup_pass(Relation rel, Buffer buf, Relation heapRel, IndexTuple newitem,
 				minoff,
 				maxoff;
 	Page		page = BufferGetPage(buf);
-	BTPageOpaque opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	BTPageOpaque opaque = BTPageGetOpaque(page);
 	Page		newpage;
 	BTDedupState state;
 	Size		pagesaving = 0;
@@ -231,7 +231,7 @@ _bt_dedup_pass(Relation rel, Buffer buf, Relation heapRel, IndexTuple newitem,
 	 */
 	if (P_HAS_GARBAGE(opaque))
 	{
-		BTPageOpaque nopaque = (BTPageOpaque) PageGetSpecialPointer(newpage);
+		BTPageOpaque nopaque = BTPageGetOpaque(newpage);
 
 		nopaque->btpo_flags &= ~BTP_HAS_GARBAGE;
 	}
@@ -310,7 +310,7 @@ _bt_bottomupdel_pass(Relation rel, Buffer buf, Relation heapRel,
 				minoff,
 				maxoff;
 	Page		page = BufferGetPage(buf);
-	BTPageOpaque opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	BTPageOpaque opaque = BTPageGetOpaque(page);
 	BTDedupState state;
 	TM_IndexDeleteOp delstate;
 	bool		neverdedup;
diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c
index 68628ec000..f6f4af8bfe 100644
--- a/src/backend/access/nbtree/nbtinsert.c
+++ b/src/backend/access/nbtree/nbtinsert.c
@@ -329,7 +329,7 @@ _bt_search_insert(Relation rel, BTInsertState insertstate)
 
 			_bt_checkpage(rel, insertstate->buf);
 			page = BufferGetPage(insertstate->buf);
-			opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+			opaque = BTPageGetOpaque(page);
 
 			/*
 			 * Check if the page is still the rightmost leaf page and has
@@ -428,7 +428,7 @@ _bt_check_unique(Relation rel, BTInsertState insertstate, Relation heapRel,
 	InitDirtySnapshot(SnapshotDirty);
 
 	page = BufferGetPage(insertstate->buf);
-	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	opaque = BTPageGetOpaque(page);
 	maxoff = PageGetMaxOffsetNumber(page);
 
 	/*
@@ -733,7 +733,7 @@ _bt_check_unique(Relation rel, BTInsertState insertstate, Relation heapRel,
 
 				nbuf = _bt_relandgetbuf(rel, nbuf, nblkno, BT_READ);
 				page = BufferGetPage(nbuf);
-				opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+				opaque = BTPageGetOpaque(page);
 				if (!P_IGNORE(opaque))
 					break;
 				if (P_RIGHTMOST(opaque))
@@ -822,7 +822,7 @@ _bt_findinsertloc(Relation rel,
 	BTPageOpaque opaque;
 	OffsetNumber newitemoff;
 
-	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	opaque = BTPageGetOpaque(page);
 
 	/* Check 1/3 of a page restriction */
 	if (unlikely(insertstate->itemsz > BTMaxItemSize(page)))
@@ -888,7 +888,7 @@ _bt_findinsertloc(Relation rel,
 				_bt_stepright(rel, insertstate, stack);
 				/* Update local state after stepping right */
 				page = BufferGetPage(insertstate->buf);
-				opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+				opaque = BTPageGetOpaque(page);
 				/* Assume duplicates (if checkingunique) */
 				uniquedup = true;
 			}
@@ -972,7 +972,7 @@ _bt_findinsertloc(Relation rel,
 			_bt_stepright(rel, insertstate, stack);
 			/* Update local state after stepping right */
 			page = BufferGetPage(insertstate->buf);
-			opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+			opaque = BTPageGetOpaque(page);
 		}
 	}
 
@@ -1030,7 +1030,7 @@ _bt_stepright(Relation rel, BTInsertState insertstate, BTStack stack)
 	BlockNumber rblkno;
 
 	page = BufferGetPage(insertstate->buf);
-	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	opaque = BTPageGetOpaque(page);
 
 	rbuf = InvalidBuffer;
 	rblkno = opaque->btpo_next;
@@ -1038,7 +1038,7 @@ _bt_stepright(Relation rel, BTInsertState insertstate, BTStack stack)
 	{
 		rbuf = _bt_relandgetbuf(rel, rbuf, rblkno, BT_WRITE);
 		page = BufferGetPage(rbuf);
-		opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+		opaque = BTPageGetOpaque(page);
 
 		/*
 		 * If this page was incompletely split, finish the split now.  We do
@@ -1120,7 +1120,7 @@ _bt_insertonpg(Relation rel,
 	IndexTuple	nposting = NULL;
 
 	page = BufferGetPage(buf);
-	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	opaque = BTPageGetOpaque(page);
 	isleaf = P_ISLEAF(opaque);
 	isroot = P_ISROOT(opaque);
 	isrightmost = P_RIGHTMOST(opaque);
@@ -1296,7 +1296,7 @@ _bt_insertonpg(Relation rel,
 		if (!isleaf)
 		{
 			Page		cpage = BufferGetPage(cbuf);
-			BTPageOpaque cpageop = (BTPageOpaque) PageGetSpecialPointer(cpage);
+			BTPageOpaque cpageop = BTPageGetOpaque(cpage);
 
 			Assert(P_INCOMPLETE_SPLIT(cpageop));
 			cpageop->btpo_flags &= ~BTP_INCOMPLETE_SPLIT;
@@ -1504,7 +1504,7 @@ _bt_split(Relation rel, BTScanInsert itup_key, Buffer buf, Buffer cbuf,
 	 * only workspace.
 	 */
 	origpage = BufferGetPage(buf);
-	oopaque = (BTPageOpaque) PageGetSpecialPointer(origpage);
+	oopaque = BTPageGetOpaque(origpage);
 	isleaf = P_ISLEAF(oopaque);
 	isrightmost = P_RIGHTMOST(oopaque);
 	maxoff = PageGetMaxOffsetNumber(origpage);
@@ -1540,7 +1540,7 @@ _bt_split(Relation rel, BTScanInsert itup_key, Buffer buf, Buffer cbuf,
 	/* Allocate temp buffer for leftpage */
 	leftpage = PageGetTempPage(origpage);
 	_bt_pageinit(leftpage, BufferGetPageSize(buf));
-	lopaque = (BTPageOpaque) PageGetSpecialPointer(leftpage);
+	lopaque = BTPageGetOpaque(leftpage);
 
 	/*
 	 * leftpage won't be the root when we're done.  Also, clear the SPLIT_END
@@ -1716,7 +1716,7 @@ _bt_split(Relation rel, BTScanInsert itup_key, Buffer buf, Buffer cbuf,
 	rightpage = BufferGetPage(rbuf);
 	rightpagenumber = BufferGetBlockNumber(rbuf);
 	/* rightpage was initialized by _bt_getbuf */
-	ropaque = (BTPageOpaque) PageGetSpecialPointer(rightpage);
+	ropaque = BTPageGetOpaque(rightpage);
 
 	/*
 	 * Finish off remaining leftpage special area fields.  They cannot be set
@@ -1887,7 +1887,7 @@ _bt_split(Relation rel, BTScanInsert itup_key, Buffer buf, Buffer cbuf,
 	{
 		sbuf = _bt_getbuf(rel, oopaque->btpo_next, BT_WRITE);
 		spage = BufferGetPage(sbuf);
-		sopaque = (BTPageOpaque) PageGetSpecialPointer(spage);
+		sopaque = BTPageGetOpaque(spage);
 		if (sopaque->btpo_prev != origpagenumber)
 		{
 			memset(rightpage, 0, BufferGetPageSize(rbuf));
@@ -1952,7 +1952,7 @@ _bt_split(Relation rel, BTScanInsert itup_key, Buffer buf, Buffer cbuf,
 	if (!isleaf)
 	{
 		Page		cpage = BufferGetPage(cbuf);
-		BTPageOpaque cpageop = (BTPageOpaque) PageGetSpecialPointer(cpage);
+		BTPageOpaque cpageop = BTPageGetOpaque(cpage);
 
 		cpageop->btpo_flags &= ~BTP_INCOMPLETE_SPLIT;
 		MarkBufferDirty(cbuf);
@@ -2139,7 +2139,7 @@ _bt_insert_parent(Relation rel,
 			BTPageOpaque opaque;
 
 			elog(DEBUG2, "concurrent ROOT page split");
-			opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+			opaque = BTPageGetOpaque(page);
 
 			/*
 			 * We should never reach here when a leaf page split takes place
@@ -2230,7 +2230,7 @@ void
 _bt_finish_split(Relation rel, Buffer lbuf, BTStack stack)
 {
 	Page		lpage = BufferGetPage(lbuf);
-	BTPageOpaque lpageop = (BTPageOpaque) PageGetSpecialPointer(lpage);
+	BTPageOpaque lpageop = BTPageGetOpaque(lpage);
 	Buffer		rbuf;
 	Page		rpage;
 	BTPageOpaque rpageop;
@@ -2242,7 +2242,7 @@ _bt_finish_split(Relation rel, Buffer lbuf, BTStack stack)
 	/* Lock right sibling, the one missing the downlink */
 	rbuf = _bt_getbuf(rel, lpageop->btpo_next, BT_WRITE);
 	rpage = BufferGetPage(rbuf);
-	rpageop = (BTPageOpaque) PageGetSpecialPointer(rpage);
+	rpageop = BTPageGetOpaque(rpage);
 
 	/* Could this be a root split? */
 	if (!stack)
@@ -2320,7 +2320,7 @@ _bt_getstackbuf(Relation rel, BTStack stack, BlockNumber child)
 
 		buf = _bt_getbuf(rel, blkno, BT_WRITE);
 		page = BufferGetPage(buf);
-		opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+		opaque = BTPageGetOpaque(page);
 
 		if (P_INCOMPLETE_SPLIT(opaque))
 		{
@@ -2451,7 +2451,7 @@ _bt_newroot(Relation rel, Buffer lbuf, Buffer rbuf)
 	lbkno = BufferGetBlockNumber(lbuf);
 	rbkno = BufferGetBlockNumber(rbuf);
 	lpage = BufferGetPage(lbuf);
-	lopaque = (BTPageOpaque) PageGetSpecialPointer(lpage);
+	lopaque = BTPageGetOpaque(lpage);
 
 	/* get a new root page */
 	rootbuf = _bt_getbuf(rel, P_NEW, BT_WRITE);
@@ -2492,11 +2492,11 @@ _bt_newroot(Relation rel, Buffer lbuf, Buffer rbuf)
 		_bt_upgrademetapage(metapg);
 
 	/* set btree special data */
-	rootopaque = (BTPageOpaque) PageGetSpecialPointer(rootpage);
+	rootopaque = BTPageGetOpaque(rootpage);
 	rootopaque->btpo_prev = rootopaque->btpo_next = P_NONE;
 	rootopaque->btpo_flags = BTP_ROOT;
 	rootopaque->btpo_level =
-		((BTPageOpaque) PageGetSpecialPointer(lpage))->btpo_level + 1;
+		(BTPageGetOpaque(lpage))->btpo_level + 1;
 	rootopaque->btpo_cycleid = 0;
 
 	/* update metapage data */
@@ -2680,7 +2680,7 @@ _bt_delete_or_dedup_one_page(Relation rel, Relation heapRel,
 	Buffer		buffer = insertstate->buf;
 	BTScanInsert itup_key = insertstate->itup_key;
 	Page		page = BufferGetPage(buffer);
-	BTPageOpaque opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	BTPageOpaque opaque = BTPageGetOpaque(page);
 
 	Assert(P_ISLEAF(opaque));
 	Assert(simpleonly || itup_key->heapkeyspace);
diff --git a/src/backend/access/nbtree/nbtpage.c b/src/backend/access/nbtree/nbtpage.c
index 6b5f01e1d0..20adb602a4 100644
--- a/src/backend/access/nbtree/nbtpage.c
+++ b/src/backend/access/nbtree/nbtpage.c
@@ -85,7 +85,7 @@ _bt_initmetapage(Page page, BlockNumber rootbknum, uint32 level,
 	metad->btm_last_cleanup_num_heap_tuples = -1.0;
 	metad->btm_allequalimage = allequalimage;
 
-	metaopaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	metaopaque = BTPageGetOpaque(page);
 	metaopaque->btpo_flags = BTP_META;
 
 	/*
@@ -112,7 +112,7 @@ _bt_upgrademetapage(Page page)
 	BTPageOpaque metaopaque PG_USED_FOR_ASSERTS_ONLY;
 
 	metad = BTPageGetMeta(page);
-	metaopaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	metaopaque = BTPageGetOpaque(page);
 
 	/* It must be really a meta page of upgradable version */
 	Assert(metaopaque->btpo_flags & BTP_META);
@@ -148,7 +148,7 @@ _bt_getmeta(Relation rel, Buffer metabuf)
 	BTMetaPageData *metad;
 
 	metapg = BufferGetPage(metabuf);
-	metaopaque = (BTPageOpaque) PageGetSpecialPointer(metapg);
+	metaopaque = BTPageGetOpaque(metapg);
 	metad = BTPageGetMeta(metapg);
 
 	/* sanity-check the metapage */
@@ -372,7 +372,7 @@ _bt_getroot(Relation rel, int access)
 
 		rootbuf = _bt_getbuf(rel, rootblkno, BT_READ);
 		rootpage = BufferGetPage(rootbuf);
-		rootopaque = (BTPageOpaque) PageGetSpecialPointer(rootpage);
+		rootopaque = BTPageGetOpaque(rootpage);
 
 		/*
 		 * Since the cache might be stale, we check the page more carefully
@@ -440,7 +440,7 @@ _bt_getroot(Relation rel, int access)
 		rootbuf = _bt_getbuf(rel, P_NEW, BT_WRITE);
 		rootblkno = BufferGetBlockNumber(rootbuf);
 		rootpage = BufferGetPage(rootbuf);
-		rootopaque = (BTPageOpaque) PageGetSpecialPointer(rootpage);
+		rootopaque = BTPageGetOpaque(rootpage);
 		rootopaque->btpo_prev = rootopaque->btpo_next = P_NONE;
 		rootopaque->btpo_flags = (BTP_LEAF | BTP_ROOT);
 		rootopaque->btpo_level = 0;
@@ -534,7 +534,7 @@ _bt_getroot(Relation rel, int access)
 		{
 			rootbuf = _bt_relandgetbuf(rel, rootbuf, rootblkno, BT_READ);
 			rootpage = BufferGetPage(rootbuf);
-			rootopaque = (BTPageOpaque) PageGetSpecialPointer(rootpage);
+			rootopaque = BTPageGetOpaque(rootpage);
 
 			if (!P_IGNORE(rootopaque))
 				break;
@@ -598,7 +598,7 @@ _bt_gettrueroot(Relation rel)
 
 	metabuf = _bt_getbuf(rel, BTREE_METAPAGE, BT_READ);
 	metapg = BufferGetPage(metabuf);
-	metaopaque = (BTPageOpaque) PageGetSpecialPointer(metapg);
+	metaopaque = BTPageGetOpaque(metapg);
 	metad = BTPageGetMeta(metapg);
 
 	if (!P_ISMETA(metaopaque) ||
@@ -637,7 +637,7 @@ _bt_gettrueroot(Relation rel)
 	{
 		rootbuf = _bt_relandgetbuf(rel, rootbuf, rootblkno, BT_READ);
 		rootpage = BufferGetPage(rootbuf);
-		rootopaque = (BTPageOpaque) PageGetSpecialPointer(rootpage);
+		rootopaque = BTPageGetOpaque(rootpage);
 
 		if (!P_IGNORE(rootopaque))
 			break;
@@ -1220,7 +1220,7 @@ _bt_delitems_vacuum(Relation rel, Buffer buf,
 	 * We can clear the vacuum cycle ID since this page has certainly been
 	 * processed by the current vacuum scan.
 	 */
-	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	opaque = BTPageGetOpaque(page);
 	opaque->btpo_cycleid = 0;
 
 	/*
@@ -1338,7 +1338,7 @@ _bt_delitems_delete(Relation rel, Buffer buf, TransactionId latestRemovedXid,
 	 * Unlike _bt_delitems_vacuum, we *must not* clear the vacuum cycle ID at
 	 * this point.  The VACUUM command alone controls vacuum cycle IDs.
 	 */
-	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	opaque = BTPageGetOpaque(page);
 
 	/*
 	 * Clear the BTP_HAS_GARBAGE page flag.
@@ -1718,7 +1718,7 @@ _bt_leftsib_splitflag(Relation rel, BlockNumber leftsib, BlockNumber target)
 
 	buf = _bt_getbuf(rel, leftsib, BT_READ);
 	page = BufferGetPage(buf);
-	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	opaque = BTPageGetOpaque(page);
 
 	/*
 	 * If the left sibling was concurrently split, so that its next-pointer
@@ -1773,7 +1773,7 @@ _bt_rightsib_halfdeadflag(Relation rel, BlockNumber leafrightsib)
 
 	buf = _bt_getbuf(rel, leafrightsib, BT_READ);
 	page = BufferGetPage(buf);
-	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	opaque = BTPageGetOpaque(page);
 
 	Assert(P_ISLEAF(opaque) && !P_ISDELETED(opaque));
 	result = P_ISHALFDEAD(opaque);
@@ -1842,7 +1842,7 @@ _bt_pagedel(Relation rel, Buffer leafbuf, BTVacState *vstate)
 	for (;;)
 	{
 		page = BufferGetPage(leafbuf);
-		opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+		opaque = BTPageGetOpaque(page);
 
 		/*
 		 * Internal pages are never deleted directly, only as part of deleting
@@ -2099,7 +2099,7 @@ _bt_mark_page_halfdead(Relation rel, Buffer leafbuf, BTStack stack)
 	IndexTupleData trunctuple;
 
 	page = BufferGetPage(leafbuf);
-	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	opaque = BTPageGetOpaque(page);
 
 	Assert(!P_RIGHTMOST(opaque) && !P_ISROOT(opaque) &&
 		   P_ISLEAF(opaque) && !P_IGNORE(opaque) &&
@@ -2154,7 +2154,7 @@ _bt_mark_page_halfdead(Relation rel, Buffer leafbuf, BTStack stack)
 	 * before entering the critical section --- otherwise it'd be a PANIC.
 	 */
 	page = BufferGetPage(subtreeparent);
-	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	opaque = BTPageGetOpaque(page);
 
 #ifdef USE_ASSERT_CHECKING
 
@@ -2201,7 +2201,7 @@ _bt_mark_page_halfdead(Relation rel, Buffer leafbuf, BTStack stack)
 	 * nbtree/README.
 	 */
 	page = BufferGetPage(subtreeparent);
-	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	opaque = BTPageGetOpaque(page);
 
 	itemid = PageGetItemId(page, poffset);
 	itup = (IndexTuple) PageGetItem(page, itemid);
@@ -2216,7 +2216,7 @@ _bt_mark_page_halfdead(Relation rel, Buffer leafbuf, BTStack stack)
 	 * is set to InvalidBlockNumber.
 	 */
 	page = BufferGetPage(leafbuf);
-	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	opaque = BTPageGetOpaque(page);
 	opaque->btpo_flags |= BTP_HALF_DEAD;
 
 	Assert(PageGetMaxOffsetNumber(page) == P_HIKEY);
@@ -2253,7 +2253,7 @@ _bt_mark_page_halfdead(Relation rel, Buffer leafbuf, BTStack stack)
 		XLogRegisterBuffer(1, subtreeparent, REGBUF_STANDARD);
 
 		page = BufferGetPage(leafbuf);
-		opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+		opaque = BTPageGetOpaque(page);
 		xlrec.leftblk = opaque->btpo_prev;
 		xlrec.rightblk = opaque->btpo_next;
 
@@ -2325,7 +2325,7 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, BlockNumber scanblkno,
 	BlockNumber leaftopparent;
 
 	page = BufferGetPage(leafbuf);
-	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	opaque = BTPageGetOpaque(page);
 
 	Assert(P_ISLEAF(opaque) && !P_ISDELETED(opaque) && P_ISHALFDEAD(opaque));
 
@@ -2364,7 +2364,7 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, BlockNumber scanblkno,
 		/* Fetch the block number of the target's left sibling */
 		buf = _bt_getbuf(rel, target, BT_READ);
 		page = BufferGetPage(buf);
-		opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+		opaque = BTPageGetOpaque(page);
 		leftsib = opaque->btpo_prev;
 		targetlevel = opaque->btpo_level;
 		Assert(targetlevel > 0);
@@ -2391,7 +2391,7 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, BlockNumber scanblkno,
 	{
 		lbuf = _bt_getbuf(rel, leftsib, BT_WRITE);
 		page = BufferGetPage(lbuf);
-		opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+		opaque = BTPageGetOpaque(page);
 		while (P_ISDELETED(opaque) || opaque->btpo_next != target)
 		{
 			bool		leftsibvalid = true;
@@ -2441,7 +2441,7 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, BlockNumber scanblkno,
 			/* step right one page */
 			lbuf = _bt_getbuf(rel, leftsib, BT_WRITE);
 			page = BufferGetPage(lbuf);
-			opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+			opaque = BTPageGetOpaque(page);
 		}
 	}
 	else
@@ -2450,7 +2450,7 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, BlockNumber scanblkno,
 	/* Next write-lock the target page itself */
 	_bt_lockbuf(rel, buf, BT_WRITE);
 	page = BufferGetPage(buf);
-	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	opaque = BTPageGetOpaque(page);
 
 	/*
 	 * Check page is still empty etc, else abandon deletion.  This is just for
@@ -2505,7 +2505,7 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, BlockNumber scanblkno,
 	rightsib = opaque->btpo_next;
 	rbuf = _bt_getbuf(rel, rightsib, BT_WRITE);
 	page = BufferGetPage(rbuf);
-	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	opaque = BTPageGetOpaque(page);
 	if (opaque->btpo_prev != target)
 		ereport(ERROR,
 				(errcode(ERRCODE_INDEX_CORRUPTED),
@@ -2528,7 +2528,7 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, BlockNumber scanblkno,
 	if (leftsib == P_NONE && rightsib_is_rightmost)
 	{
 		page = BufferGetPage(rbuf);
-		opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+		opaque = BTPageGetOpaque(page);
 		if (P_RIGHTMOST(opaque))
 		{
 			/* rightsib will be the only one left on the level */
@@ -2565,12 +2565,12 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, BlockNumber scanblkno,
 	if (BufferIsValid(lbuf))
 	{
 		page = BufferGetPage(lbuf);
-		opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+		opaque = BTPageGetOpaque(page);
 		Assert(opaque->btpo_next == target);
 		opaque->btpo_next = rightsib;
 	}
 	page = BufferGetPage(rbuf);
-	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	opaque = BTPageGetOpaque(page);
 	Assert(opaque->btpo_prev == target);
 	opaque->btpo_prev = leftsib;
 
@@ -2599,7 +2599,7 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, BlockNumber scanblkno,
 	 * of that scan.
 	 */
 	page = BufferGetPage(buf);
-	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	opaque = BTPageGetOpaque(page);
 	Assert(P_ISHALFDEAD(opaque) || !P_ISLEAF(opaque));
 
 	/*
@@ -2814,7 +2814,7 @@ _bt_lock_subtree_parent(Relation rel, BlockNumber child, BTStack stack,
 	parentoffset = stack->bts_offset;
 
 	page = BufferGetPage(pbuf);
-	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	opaque = BTPageGetOpaque(page);
 	maxoff = PageGetMaxOffsetNumber(page);
 	leftsibparent = opaque->btpo_prev;
 
diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c
index dacf3f7a58..06131f23d4 100644
--- a/src/backend/access/nbtree/nbtree.c
+++ b/src/backend/access/nbtree/nbtree.c
@@ -1070,7 +1070,7 @@ backtrack:
 	if (!PageIsNew(page))
 	{
 		_bt_checkpage(rel, buf);
-		opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+		opaque = BTPageGetOpaque(page);
 	}
 
 	Assert(blkno <= scanblkno);
diff --git a/src/backend/access/nbtree/nbtsearch.c b/src/backend/access/nbtree/nbtsearch.c
index 9d82d4904d..c74543bfde 100644
--- a/src/backend/access/nbtree/nbtsearch.c
+++ b/src/backend/access/nbtree/nbtsearch.c
@@ -134,7 +134,7 @@ _bt_search(Relation rel, BTScanInsert key, Buffer *bufP, int access,
 
 		/* if this is a leaf page, we're done */
 		page = BufferGetPage(*bufP);
-		opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+		opaque = BTPageGetOpaque(page);
 		if (P_ISLEAF(opaque))
 			break;
 
@@ -268,7 +268,7 @@ _bt_moveright(Relation rel,
 	{
 		page = BufferGetPage(buf);
 		TestForOldSnapshot(snapshot, rel, page);
-		opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+		opaque = BTPageGetOpaque(page);
 
 		if (P_RIGHTMOST(opaque))
 			break;
@@ -347,7 +347,7 @@ _bt_binsrch(Relation rel,
 				cmpval;
 
 	page = BufferGetPage(buf);
-	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	opaque = BTPageGetOpaque(page);
 
 	/* Requesting nextkey semantics while using scantid seems nonsensical */
 	Assert(!key->nextkey || key->scantid == NULL);
@@ -451,7 +451,7 @@ _bt_binsrch_insert(Relation rel, BTInsertState insertstate)
 				cmpval;
 
 	page = BufferGetPage(insertstate->buf);
-	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	opaque = BTPageGetOpaque(page);
 
 	Assert(P_ISLEAF(opaque));
 	Assert(!key->nextkey);
@@ -659,7 +659,7 @@ _bt_compare(Relation rel,
 			OffsetNumber offnum)
 {
 	TupleDesc	itupdesc = RelationGetDescr(rel);
-	BTPageOpaque opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	BTPageOpaque opaque = BTPageGetOpaque(page);
 	IndexTuple	itup;
 	ItemPointer heapTid;
 	ScanKey		scankey;
@@ -1536,7 +1536,7 @@ _bt_readpage(IndexScanDesc scan, ScanDirection dir, OffsetNumber offnum)
 	Assert(BufferIsValid(so->currPos.buf));
 
 	page = BufferGetPage(so->currPos.buf);
-	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	opaque = BTPageGetOpaque(page);
 
 	/* allow next page be processed by parallel worker */
 	if (scan->parallel_scan)
@@ -2007,7 +2007,7 @@ _bt_readnextpage(IndexScanDesc scan, BlockNumber blkno, ScanDirection dir)
 			so->currPos.buf = _bt_getbuf(rel, blkno, BT_READ);
 			page = BufferGetPage(so->currPos.buf);
 			TestForOldSnapshot(scan->xs_snapshot, rel, page);
-			opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+			opaque = BTPageGetOpaque(page);
 			/* check for deleted page */
 			if (!P_IGNORE(opaque))
 			{
@@ -2110,7 +2110,7 @@ _bt_readnextpage(IndexScanDesc scan, BlockNumber blkno, ScanDirection dir)
 			 */
 			page = BufferGetPage(so->currPos.buf);
 			TestForOldSnapshot(scan->xs_snapshot, rel, page);
-			opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+			opaque = BTPageGetOpaque(page);
 			if (!P_IGNORE(opaque))
 			{
 				PredicateLockPage(rel, BufferGetBlockNumber(so->currPos.buf), scan->xs_snapshot);
@@ -2191,7 +2191,7 @@ _bt_walk_left(Relation rel, Buffer buf, Snapshot snapshot)
 	BTPageOpaque opaque;
 
 	page = BufferGetPage(buf);
-	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	opaque = BTPageGetOpaque(page);
 
 	for (;;)
 	{
@@ -2216,7 +2216,7 @@ _bt_walk_left(Relation rel, Buffer buf, Snapshot snapshot)
 		buf = _bt_getbuf(rel, blkno, BT_READ);
 		page = BufferGetPage(buf);
 		TestForOldSnapshot(snapshot, rel, page);
-		opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+		opaque = BTPageGetOpaque(page);
 
 		/*
 		 * If this isn't the page we want, walk right till we find what we
@@ -2243,14 +2243,14 @@ _bt_walk_left(Relation rel, Buffer buf, Snapshot snapshot)
 			buf = _bt_relandgetbuf(rel, buf, blkno, BT_READ);
 			page = BufferGetPage(buf);
 			TestForOldSnapshot(snapshot, rel, page);
-			opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+			opaque = BTPageGetOpaque(page);
 		}
 
 		/* Return to the original page to see what's up */
 		buf = _bt_relandgetbuf(rel, buf, obknum, BT_READ);
 		page = BufferGetPage(buf);
 		TestForOldSnapshot(snapshot, rel, page);
-		opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+		opaque = BTPageGetOpaque(page);
 		if (P_ISDELETED(opaque))
 		{
 			/*
@@ -2268,7 +2268,7 @@ _bt_walk_left(Relation rel, Buffer buf, Snapshot snapshot)
 				buf = _bt_relandgetbuf(rel, buf, blkno, BT_READ);
 				page = BufferGetPage(buf);
 				TestForOldSnapshot(snapshot, rel, page);
-				opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+				opaque = BTPageGetOpaque(page);
 				if (!P_ISDELETED(opaque))
 					break;
 			}
@@ -2329,7 +2329,7 @@ _bt_get_endpoint(Relation rel, uint32 level, bool rightmost,
 
 	page = BufferGetPage(buf);
 	TestForOldSnapshot(snapshot, rel, page);
-	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	opaque = BTPageGetOpaque(page);
 
 	for (;;)
 	{
@@ -2349,7 +2349,7 @@ _bt_get_endpoint(Relation rel, uint32 level, bool rightmost,
 			buf = _bt_relandgetbuf(rel, buf, blkno, BT_READ);
 			page = BufferGetPage(buf);
 			TestForOldSnapshot(snapshot, rel, page);
-			opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+			opaque = BTPageGetOpaque(page);
 		}
 
 		/* Done? */
@@ -2372,7 +2372,7 @@ _bt_get_endpoint(Relation rel, uint32 level, bool rightmost,
 
 		buf = _bt_relandgetbuf(rel, buf, blkno, BT_READ);
 		page = BufferGetPage(buf);
-		opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+		opaque = BTPageGetOpaque(page);
 	}
 
 	return buf;
@@ -2418,7 +2418,7 @@ _bt_endpoint(IndexScanDesc scan, ScanDirection dir)
 
 	PredicateLockPage(rel, BufferGetBlockNumber(buf), scan->xs_snapshot);
 	page = BufferGetPage(buf);
-	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	opaque = BTPageGetOpaque(page);
 	Assert(P_ISLEAF(opaque));
 
 	if (ScanDirectionIsForward(dir))
diff --git a/src/backend/access/nbtree/nbtsort.c b/src/backend/access/nbtree/nbtsort.c
index 8a19de2f66..c074513efa 100644
--- a/src/backend/access/nbtree/nbtsort.c
+++ b/src/backend/access/nbtree/nbtsort.c
@@ -625,7 +625,7 @@ _bt_blnewpage(uint32 level)
 	_bt_pageinit(page, BLCKSZ);
 
 	/* Initialize BT opaque state */
-	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	opaque = BTPageGetOpaque(page);
 	opaque->btpo_prev = opaque->btpo_next = P_NONE;
 	opaque->btpo_level = level;
 	opaque->btpo_flags = (level > 0) ? 0 : BTP_LEAF;
@@ -1000,9 +1000,9 @@ _bt_buildadd(BTWriteState *wstate, BTPageState *state, IndexTuple itup,
 		Assert((BTreeTupleGetNAtts(state->btps_lowkey, wstate->index) <=
 				IndexRelationGetNumberOfKeyAttributes(wstate->index) &&
 				BTreeTupleGetNAtts(state->btps_lowkey, wstate->index) > 0) ||
-			   P_LEFTMOST((BTPageOpaque) PageGetSpecialPointer(opage)));
+			   P_LEFTMOST(BTPageGetOpaque(opage)));
 		Assert(BTreeTupleGetNAtts(state->btps_lowkey, wstate->index) == 0 ||
-			   !P_LEFTMOST((BTPageOpaque) PageGetSpecialPointer(opage)));
+			   !P_LEFTMOST(BTPageGetOpaque(opage)));
 		BTreeTupleSetDownLink(state->btps_lowkey, oblkno);
 		_bt_buildadd(wstate, state->btps_next, state->btps_lowkey, 0);
 		pfree(state->btps_lowkey);
@@ -1017,8 +1017,8 @@ _bt_buildadd(BTWriteState *wstate, BTPageState *state, IndexTuple itup,
 		 * Set the sibling links for both pages.
 		 */
 		{
-			BTPageOpaque oopaque = (BTPageOpaque) PageGetSpecialPointer(opage);
-			BTPageOpaque nopaque = (BTPageOpaque) PageGetSpecialPointer(npage);
+			BTPageOpaque oopaque = BTPageGetOpaque(opage);
+			BTPageOpaque nopaque = BTPageGetOpaque(npage);
 
 			oopaque->btpo_next = nblkno;
 			nopaque->btpo_prev = oblkno;
@@ -1125,7 +1125,7 @@ _bt_uppershutdown(BTWriteState *wstate, BTPageState *state)
 		BTPageOpaque opaque;
 
 		blkno = s->btps_blkno;
-		opaque = (BTPageOpaque) PageGetSpecialPointer(s->btps_page);
+		opaque = BTPageGetOpaque(s->btps_page);
 
 		/*
 		 * We have to link the last page on this level to somewhere.
diff --git a/src/backend/access/nbtree/nbtsplitloc.c b/src/backend/access/nbtree/nbtsplitloc.c
index c46594e1a2..ee01ceafda 100644
--- a/src/backend/access/nbtree/nbtsplitloc.c
+++ b/src/backend/access/nbtree/nbtsplitloc.c
@@ -152,7 +152,7 @@ _bt_findsplitloc(Relation rel,
 	SplitPoint	leftpage,
 				rightpage;
 
-	opaque = (BTPageOpaque) PageGetSpecialPointer(origpage);
+	opaque = BTPageGetOpaque(origpage);
 	maxoff = PageGetMaxOffsetNumber(origpage);
 
 	/* Total free space available on a btree page, after fixed overhead */
diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c
index 84164748b3..96c72fc432 100644
--- a/src/backend/access/nbtree/nbtutils.c
+++ b/src/backend/access/nbtree/nbtutils.c
@@ -1774,7 +1774,7 @@ _bt_killitems(IndexScanDesc scan)
 		}
 	}
 
-	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	opaque = BTPageGetOpaque(page);
 	minoff = P_FIRSTDATAKEY(opaque);
 	maxoff = PageGetMaxOffsetNumber(page);
 
@@ -2474,7 +2474,7 @@ _bt_check_natts(Relation rel, bool heapkeyspace, Page page, OffsetNumber offnum)
 {
 	int16		natts = IndexRelationGetNumberOfAttributes(rel);
 	int16		nkeyatts = IndexRelationGetNumberOfKeyAttributes(rel);
-	BTPageOpaque opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	BTPageOpaque opaque = BTPageGetOpaque(page);
 	IndexTuple	itup;
 	int			tupnatts;
 
@@ -2662,7 +2662,7 @@ _bt_check_third_page(Relation rel, Relation heap, bool needheaptidspace,
 	 * Internal page insertions cannot fail here, because that would mean that
 	 * an earlier leaf level insertion that should have failed didn't
 	 */
-	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	opaque = BTPageGetOpaque(page);
 	if (!P_ISLEAF(opaque))
 		elog(ERROR, "cannot insert oversized tuple of size %zu on internal page of index \"%s\"",
 			 itemsz, RelationGetRelationName(rel));
diff --git a/src/backend/access/nbtree/nbtxlog.c b/src/backend/access/nbtree/nbtxlog.c
index 611f412ba8..fba124b940 100644
--- a/src/backend/access/nbtree/nbtxlog.c
+++ b/src/backend/access/nbtree/nbtxlog.c
@@ -115,7 +115,7 @@ _bt_restore_meta(XLogReaderState *record, uint8 block_id)
 	md->btm_last_cleanup_num_heap_tuples = -1.0;
 	md->btm_allequalimage = xlrec->allequalimage;
 
-	pageop = (BTPageOpaque) PageGetSpecialPointer(metapg);
+	pageop = BTPageGetOpaque(metapg);
 	pageop->btpo_flags = BTP_META;
 
 	/*
@@ -146,7 +146,7 @@ _bt_clear_incomplete_split(XLogReaderState *record, uint8 block_id)
 	if (XLogReadBufferForRedo(record, block_id, &buf) == BLK_NEEDS_REDO)
 	{
 		Page		page = (Page) BufferGetPage(buf);
-		BTPageOpaque pageop = (BTPageOpaque) PageGetSpecialPointer(page);
+		BTPageOpaque pageop = BTPageGetOpaque(page);
 
 		Assert(P_INCOMPLETE_SPLIT(pageop));
 		pageop->btpo_flags &= ~BTP_INCOMPLETE_SPLIT;
@@ -292,7 +292,7 @@ btree_xlog_split(bool newitemonleft, XLogReaderState *record)
 	rpage = (Page) BufferGetPage(rbuf);
 
 	_bt_pageinit(rpage, BufferGetPageSize(rbuf));
-	ropaque = (BTPageOpaque) PageGetSpecialPointer(rpage);
+	ropaque = BTPageGetOpaque(rpage);
 
 	ropaque->btpo_prev = origpagenumber;
 	ropaque->btpo_next = spagenumber;
@@ -317,7 +317,7 @@ btree_xlog_split(bool newitemonleft, XLogReaderState *record)
 		 * same for the right page.
 		 */
 		Page		origpage = (Page) BufferGetPage(buf);
-		BTPageOpaque oopaque = (BTPageOpaque) PageGetSpecialPointer(origpage);
+		BTPageOpaque oopaque = BTPageGetOpaque(origpage);
 		OffsetNumber off;
 		IndexTuple	newitem = NULL,
 					left_hikey = NULL,
@@ -442,7 +442,7 @@ btree_xlog_split(bool newitemonleft, XLogReaderState *record)
 		if (XLogReadBufferForRedo(record, 2, &sbuf) == BLK_NEEDS_REDO)
 		{
 			Page		spage = (Page) BufferGetPage(sbuf);
-			BTPageOpaque spageop = (BTPageOpaque) PageGetSpecialPointer(spage);
+			BTPageOpaque spageop = BTPageGetOpaque(spage);
 
 			spageop->btpo_prev = rightpagenumber;
 
@@ -473,7 +473,7 @@ btree_xlog_dedup(XLogReaderState *record)
 	{
 		char	   *ptr = XLogRecGetBlockData(record, 0, NULL);
 		Page		page = (Page) BufferGetPage(buf);
-		BTPageOpaque opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+		BTPageOpaque opaque = BTPageGetOpaque(page);
 		OffsetNumber offnum,
 					minoff,
 					maxoff;
@@ -541,7 +541,7 @@ btree_xlog_dedup(XLogReaderState *record)
 
 		if (P_HAS_GARBAGE(opaque))
 		{
-			BTPageOpaque nopaque = (BTPageOpaque) PageGetSpecialPointer(newpage);
+			BTPageOpaque nopaque = BTPageGetOpaque(newpage);
 
 			nopaque->btpo_flags &= ~BTP_HAS_GARBAGE;
 		}
@@ -639,7 +639,7 @@ btree_xlog_vacuum(XLogReaderState *record)
 		 * Mark the page as not containing any LP_DEAD items --- see comments
 		 * in _bt_delitems_vacuum().
 		 */
-		opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+		opaque = BTPageGetOpaque(page);
 		opaque->btpo_flags &= ~BTP_HAS_GARBAGE;
 
 		PageSetLSN(page, lsn);
@@ -699,7 +699,7 @@ btree_xlog_delete(XLogReaderState *record)
 			PageIndexMultiDelete(page, (OffsetNumber *) ptr, xlrec->ndeleted);
 
 		/* Mark the page as not containing any LP_DEAD items */
-		opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+		opaque = BTPageGetOpaque(page);
 		opaque->btpo_flags &= ~BTP_HAS_GARBAGE;
 
 		PageSetLSN(page, lsn);
@@ -737,7 +737,7 @@ btree_xlog_mark_page_halfdead(uint8 info, XLogReaderState *record)
 		BlockNumber rightsib;
 
 		page = (Page) BufferGetPage(buffer);
-		pageop = (BTPageOpaque) PageGetSpecialPointer(page);
+		pageop = BTPageGetOpaque(page);
 
 		poffset = xlrec->poffset;
 
@@ -768,7 +768,7 @@ btree_xlog_mark_page_halfdead(uint8 info, XLogReaderState *record)
 	page = (Page) BufferGetPage(buffer);
 
 	_bt_pageinit(page, BufferGetPageSize(buffer));
-	pageop = (BTPageOpaque) PageGetSpecialPointer(page);
+	pageop = BTPageGetOpaque(page);
 
 	pageop->btpo_prev = xlrec->leftblk;
 	pageop->btpo_next = xlrec->rightblk;
@@ -833,7 +833,7 @@ btree_xlog_unlink_page(uint8 info, XLogReaderState *record)
 		if (XLogReadBufferForRedo(record, 1, &leftbuf) == BLK_NEEDS_REDO)
 		{
 			page = (Page) BufferGetPage(leftbuf);
-			pageop = (BTPageOpaque) PageGetSpecialPointer(page);
+			pageop = BTPageGetOpaque(page);
 			pageop->btpo_next = rightsib;
 
 			PageSetLSN(page, lsn);
@@ -848,7 +848,7 @@ btree_xlog_unlink_page(uint8 info, XLogReaderState *record)
 	page = (Page) BufferGetPage(target);
 
 	_bt_pageinit(page, BufferGetPageSize(target));
-	pageop = (BTPageOpaque) PageGetSpecialPointer(page);
+	pageop = BTPageGetOpaque(page);
 
 	pageop->btpo_prev = leftsib;
 	pageop->btpo_next = rightsib;
@@ -865,7 +865,7 @@ btree_xlog_unlink_page(uint8 info, XLogReaderState *record)
 	if (XLogReadBufferForRedo(record, 2, &rightbuf) == BLK_NEEDS_REDO)
 	{
 		page = (Page) BufferGetPage(rightbuf);
-		pageop = (BTPageOpaque) PageGetSpecialPointer(page);
+		pageop = BTPageGetOpaque(page);
 		pageop->btpo_prev = leftsib;
 
 		PageSetLSN(page, lsn);
@@ -906,7 +906,7 @@ btree_xlog_unlink_page(uint8 info, XLogReaderState *record)
 		page = (Page) BufferGetPage(leafbuf);
 
 		_bt_pageinit(page, BufferGetPageSize(leafbuf));
-		pageop = (BTPageOpaque) PageGetSpecialPointer(page);
+		pageop = BTPageGetOpaque(page);
 
 		pageop->btpo_flags = BTP_HALF_DEAD | BTP_LEAF;
 		pageop->btpo_prev = xlrec->leafleftsib;
@@ -948,7 +948,7 @@ btree_xlog_newroot(XLogReaderState *record)
 	page = (Page) BufferGetPage(buffer);
 
 	_bt_pageinit(page, BufferGetPageSize(buffer));
-	pageop = (BTPageOpaque) PageGetSpecialPointer(page);
+	pageop = BTPageGetOpaque(page);
 
 	pageop->btpo_flags = BTP_ROOT;
 	pageop->btpo_prev = pageop->btpo_next = P_NONE;
@@ -1097,7 +1097,7 @@ btree_mask(char *pagedata, BlockNumber blkno)
 	mask_page_hint_bits(page);
 	mask_unused_space(page);
 
-	maskopaq = (BTPageOpaque) PageGetSpecialPointer(page);
+	maskopaq = BTPageGetOpaque(page);
 
 	if (P_ISLEAF(maskopaq))
 	{
diff --git a/contrib/amcheck/verify_nbtree.c b/contrib/amcheck/verify_nbtree.c
index d2510ee648..70278c4f93 100644
--- a/contrib/amcheck/verify_nbtree.c
+++ b/contrib/amcheck/verify_nbtree.c
@@ -691,7 +691,7 @@ bt_check_level_from_leftmost(BtreeCheckState *state, BtreeLevel level)
 		state->target = palloc_btree_page(state, state->targetblock);
 		state->targetlsn = PageGetLSN(state->target);
 
-		opaque = (BTPageOpaque) PageGetSpecialPointer(state->target);
+		opaque = BTPageGetOpaque(state->target);
 
 		if (P_IGNORE(opaque))
 		{
@@ -927,7 +927,7 @@ bt_recheck_sibling_links(BtreeCheckState *state,
 		LockBuffer(lbuf, BT_READ);
 		_bt_checkpage(state->rel, lbuf);
 		page = BufferGetPage(lbuf);
-		opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+		opaque = BTPageGetOpaque(page);
 		if (P_ISDELETED(opaque))
 		{
 			/*
@@ -951,7 +951,7 @@ bt_recheck_sibling_links(BtreeCheckState *state,
 			LockBuffer(newtargetbuf, BT_READ);
 			_bt_checkpage(state->rel, newtargetbuf);
 			page = BufferGetPage(newtargetbuf);
-			opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+			opaque = BTPageGetOpaque(page);
 			/* btpo_prev_from_target may have changed; update it */
 			btpo_prev_from_target = opaque->btpo_prev;
 		}
@@ -1049,7 +1049,7 @@ bt_target_page_check(BtreeCheckState *state)
 	OffsetNumber max;
 	BTPageOpaque topaque;
 
-	topaque = (BTPageOpaque) PageGetSpecialPointer(state->target);
+	topaque = BTPageGetOpaque(state->target);
 	max = PageGetMaxOffsetNumber(state->target);
 
 	elog(DEBUG2, "verifying %u items on %s block %u", max,
@@ -1478,7 +1478,7 @@ bt_target_page_check(BtreeCheckState *state)
 					/* Get fresh copy of target page */
 					state->target = palloc_btree_page(state, state->targetblock);
 					/* Note that we deliberately do not update target LSN */
-					topaque = (BTPageOpaque) PageGetSpecialPointer(state->target);
+					topaque = BTPageGetOpaque(state->target);
 
 					/*
 					 * All !readonly checks now performed; just return
@@ -1552,7 +1552,7 @@ bt_right_page_check_scankey(BtreeCheckState *state)
 	OffsetNumber nline;
 
 	/* Determine target's next block number */
-	opaque = (BTPageOpaque) PageGetSpecialPointer(state->target);
+	opaque = BTPageGetOpaque(state->target);
 
 	/* If target is already rightmost, no right sibling; nothing to do here */
 	if (P_RIGHTMOST(opaque))
@@ -1588,7 +1588,7 @@ bt_right_page_check_scankey(BtreeCheckState *state)
 		CHECK_FOR_INTERRUPTS();
 
 		rightpage = palloc_btree_page(state, targetnext);
-		opaque = (BTPageOpaque) PageGetSpecialPointer(rightpage);
+		opaque = BTPageGetOpaque(rightpage);
 
 		if (!P_IGNORE(opaque) || P_RIGHTMOST(opaque))
 			break;
@@ -1893,7 +1893,7 @@ bt_child_highkey_check(BtreeCheckState *state,
 		else
 			page = palloc_btree_page(state, blkno);
 
-		opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+		opaque = BTPageGetOpaque(page);
 
 		/* The first page we visit at the level should be leftmost */
 		if (first && !BlockNumberIsValid(state->prevrightlink) && !P_LEFTMOST(opaque))
@@ -1971,7 +1971,7 @@ bt_child_highkey_check(BtreeCheckState *state,
 			else
 				pivotkey_offset = target_downlinkoffnum;
 
-			topaque = (BTPageOpaque) PageGetSpecialPointer(state->target);
+			topaque = BTPageGetOpaque(state->target);
 
 			if (!offset_is_negative_infinity(topaque, pivotkey_offset))
 			{
@@ -2128,9 +2128,9 @@ bt_child_check(BtreeCheckState *state, BTScanInsert targetkey,
 	 * Check all items, rather than checking just the first and trusting that
 	 * the operator class obeys the transitive law.
 	 */
-	topaque = (BTPageOpaque) PageGetSpecialPointer(state->target);
+	topaque = BTPageGetOpaque(state->target);
 	child = palloc_btree_page(state, childblock);
-	copaque = (BTPageOpaque) PageGetSpecialPointer(child);
+	copaque = BTPageGetOpaque(child);
 	maxoffset = PageGetMaxOffsetNumber(child);
 
 	/*
@@ -2235,7 +2235,7 @@ static void
 bt_downlink_missing_check(BtreeCheckState *state, bool rightsplit,
 						  BlockNumber blkno, Page page)
 {
-	BTPageOpaque opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	BTPageOpaque opaque = BTPageGetOpaque(page);
 	ItemId		itemid;
 	IndexTuple	itup;
 	Page		child;
@@ -2319,7 +2319,7 @@ bt_downlink_missing_check(BtreeCheckState *state, bool rightsplit,
 		CHECK_FOR_INTERRUPTS();
 
 		child = palloc_btree_page(state, childblk);
-		copaque = (BTPageOpaque) PageGetSpecialPointer(child);
+		copaque = BTPageGetOpaque(child);
 
 		if (P_ISLEAF(copaque))
 			break;
@@ -2780,7 +2780,7 @@ invariant_l_offset(BtreeCheckState *state, BTScanInsert key,
 		bool		nonpivot;
 
 		ritup = (IndexTuple) PageGetItem(state->target, itemid);
-		topaque = (BTPageOpaque) PageGetSpecialPointer(state->target);
+		topaque = BTPageGetOpaque(state->target);
 		nonpivot = P_ISLEAF(topaque) && upperbound >= P_FIRSTDATAKEY(topaque);
 
 		/* Get number of keys + heap TID for item to the right */
@@ -2895,7 +2895,7 @@ invariant_l_nontarget_offset(BtreeCheckState *state, BTScanInsert key,
 		bool		nonpivot;
 
 		child = (IndexTuple) PageGetItem(nontarget, itemid);
-		copaque = (BTPageOpaque) PageGetSpecialPointer(nontarget);
+		copaque = BTPageGetOpaque(nontarget);
 		nonpivot = P_ISLEAF(copaque) && upperbound >= P_FIRSTDATAKEY(copaque);
 
 		/* Get number of keys + heap TID for child/non-target item */
@@ -2954,7 +2954,7 @@ palloc_btree_page(BtreeCheckState *state, BlockNumber blocknum)
 	memcpy(page, BufferGetPage(buffer), BLCKSZ);
 	UnlockReleaseBuffer(buffer);
 
-	opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	opaque = BTPageGetOpaque(page);
 
 	if (P_ISMETA(opaque) && blocknum != BTREE_METAPAGE)
 		ereport(ERROR,
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index 7651c59bbf..3daa31c84d 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -93,7 +93,7 @@ GetBTPageStatistics(BlockNumber blkno, Buffer buffer, BTPageStat *stat)
 	Page		page = BufferGetPage(buffer);
 	PageHeader	phdr = (PageHeader) page;
 	OffsetNumber maxoff = PageGetMaxOffsetNumber(page);
-	BTPageOpaque opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+	BTPageOpaque opaque = BTPageGetOpaque(page);
 	int			item_size = 0;
 	int			off;
 
@@ -525,7 +525,7 @@ bt_page_items_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 
 		uargs->offset = FirstOffsetNumber;
 
-		opaque = (BTPageOpaque) PageGetSpecialPointer(uargs->page);
+		opaque = BTPageGetOpaque(uargs->page);
 
 		if (!P_ISDELETED(opaque))
 			fctx->max_calls = PageGetMaxOffsetNumber(uargs->page);
@@ -622,7 +622,7 @@ bt_page_items_bytea(PG_FUNCTION_ARGS)
 							   (int) MAXALIGN(sizeof(BTPageOpaqueData)),
 							   (int) PageGetSpecialSize(uargs->page))));
 
-		opaque = (BTPageOpaque) PageGetSpecialPointer(uargs->page);
+		opaque = BTPageGetOpaque(uargs->page);
 
 		if (P_ISMETA(opaque))
 			ereport(ERROR,
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index 6de21d6608..69af7b962f 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -72,7 +72,7 @@ verify_hash_page(bytea *raw_page, int flags)
 							   (int) MAXALIGN(sizeof(HashPageOpaqueData)),
 							   (int) PageGetSpecialSize(page))));
 
-		pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
+		pageopaque = HashPageGetOpaque(page);
 		if (pageopaque->hasho_page_id != HASHO_PAGE_ID)
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
@@ -154,7 +154,7 @@ static void
 GetHashPageStatistics(Page page, HashPageStat *stat)
 {
 	OffsetNumber maxoff = PageGetMaxOffsetNumber(page);
-	HashPageOpaque opaque = (HashPageOpaque) PageGetSpecialPointer(page);
+	HashPageOpaque opaque = HashPageGetOpaque(page);
 	int			off;
 
 	stat->dead_items = stat->live_items = 0;
@@ -206,7 +206,7 @@ hash_page_type(PG_FUNCTION_ARGS)
 		type = "unused";
 	else
 	{
-		opaque = (HashPageOpaque) PageGetSpecialPointer(page);
+		opaque = HashPageGetOpaque(page);
 
 		/* page type (flags) */
 		pagetype = opaque->hasho_flag & LH_PAGE_TYPE;
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 6c4b053dd0..e1048e47ff 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -281,7 +281,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		LockBuffer(buffer, BUFFER_LOCK_SHARE);
 
 		page = BufferGetPage(buffer);
-		opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+		opaque = BTPageGetOpaque(page);
 
 		/*
 		 * Determine page type, and update totals.
@@ -641,7 +641,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 			HashPageOpaque opaque;
 			int			pagetype;
 
-			opaque = (HashPageOpaque) PageGetSpecialPointer(page);
+			opaque = HashPageGetOpaque(page);
 			pagetype = opaque->hasho_flag & LH_PAGE_TYPE;
 
 			if (pagetype == LH_BUCKET_PAGE)
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index c9b8f01f9b..3094566908 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -415,7 +415,7 @@ pgstat_btree_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno,
 	{
 		BTPageOpaque opaque;
 
-		opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+		opaque = BTPageGetOpaque(page);
 		if (P_IGNORE(opaque))
 		{
 			/* deleted or half-dead page */
@@ -452,7 +452,7 @@ pgstat_hash_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno,
 	{
 		HashPageOpaque opaque;
 
-		opaque = (HashPageOpaque) PageGetSpecialPointer(page);
+		opaque = HashPageGetOpaque(page);
 		switch (opaque->hasho_flag & LH_PAGE_TYPE)
 		{
 			case LH_UNUSED_PAGE:
-- 
2.35.1

Attachment: signature.asc
Description: PGP signature

Reply via email to