Consistently use the XLogRecPtrIsInvalid() macro

Started by Bertrand Drouvot3 months ago47 messages
#1Bertrand Drouvot
bertranddrouvot.pg@gmail.com
20 attachment(s)

Hi hackers,

While working on refactoring some code in [1]/messages/by-id/CAD21AoB_C6V1PLNs=SuOejgGh1o6ZHJMstD7X4X1b_z==LdH1Q@mail.gmail.com, one of the changes was:

-       if (initial_restart_lsn != InvalidXLogRecPtr &&
-           initial_restart_lsn < oldestLSN)
+       XLogRecPtr  restart_lsn = s->data.restart_lsn;
+
+       if (restart_lsn != InvalidXLogRecPtr &&
+           restart_lsn < oldestLSN)

Sawada-san suggested to use the XLogRecPtrIsInvalid() macro here.

But this != InvalidXLogRecPtr check was existing code, so why not consistently
use XLogRecPtrIsInvalid() where we check equality against InvalidXLogRecPtr?

At the time the current XLogRecPtrIsInvalid() has been introduced (0ab9d1c4b316)
all the InvalidXLogRecPtr equality checks were done using XLogRecPtrIsInvalid().

But since, it has changed: I looked at it and this is not the case anymore in
20 files.

PFA, patches to $SUBJECT. To ease the review, I created one patch per modified
file.

I suspect the same approach could be applied to some other macros too. Let's
start with XLogRecPtrIsInvalid() first.

I think that's one of the things we could do once a year, like Peter does with
his annual "clang-tidy" check ([2]/messages/by-id/CAH2-WzmxPQAF_ZhwrUo3rzVk3yYj_4mqbgiQXAGGO5nFYV3D8Q@mail.gmail.com).

Thoughts?

[1]: /messages/by-id/CAD21AoB_C6V1PLNs=SuOejgGh1o6ZHJMstD7X4X1b_z==LdH1Q@mail.gmail.com
[2]: /messages/by-id/CAH2-WzmxPQAF_ZhwrUo3rzVk3yYj_4mqbgiQXAGGO5nFYV3D8Q@mail.gmail.com

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

Attachments:

v1-0001-make-use-of-XLogRecPtrIsInvalid-in-rewriteheap.c.patchtext/x-diff; charset=us-asciiDownload
From 16e7a6e300ece55efaf67bf22e9d5f5d488e5114 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Tue, 28 Oct 2025 05:39:59 +0000
Subject: [PATCH v1 01/20] make use of XLogRecPtrIsInvalid in rewriteheap.c

---
 src/backend/access/heap/rewriteheap.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
 100.0% src/backend/access/heap/

diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c
index 8061e92f044..e4cff133886 100644
--- a/src/backend/access/heap/rewriteheap.c
+++ b/src/backend/access/heap/rewriteheap.c
@@ -1169,7 +1169,7 @@ CheckPointLogicalRewriteHeap(void)
 	cutoff = ReplicationSlotsComputeLogicalRestartLSN();
 
 	/* don't start earlier than the restart lsn */
-	if (cutoff != InvalidXLogRecPtr && redo < cutoff)
+	if (!XLogRecPtrIsInvalid(cutoff) && redo < cutoff)
 		cutoff = redo;
 
 	mappings_dir = AllocateDir(PG_LOGICAL_MAPPINGS_DIR);
@@ -1204,7 +1204,7 @@ CheckPointLogicalRewriteHeap(void)
 
 		lsn = ((uint64) hi) << 32 | lo;
 
-		if (lsn < cutoff || cutoff == InvalidXLogRecPtr)
+		if (lsn < cutoff || XLogRecPtrIsInvalid(cutoff))
 		{
 			elog(DEBUG1, "removing logical rewrite file \"%s\"", path);
 			if (unlink(path) < 0)
-- 
2.34.1

v1-0002-make-use-of-XLogRecPtrIsInvalid-in-twophase.c.patchtext/x-diff; charset=us-asciiDownload
From b851563ba0efede5db4c683d7319caf029c531cb Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Tue, 28 Oct 2025 05:42:51 +0000
Subject: [PATCH v1 02/20] make use of XLogRecPtrIsInvalid in twophase.c

---
 src/backend/access/transam/twophase.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
 100.0% src/backend/access/transam/

diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 33369fbe23a..362a5afc4de 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -2198,7 +2198,7 @@ ProcessTwoPhaseBuffer(FullTransactionId fxid,
 	Assert(LWLockHeldByMeInMode(TwoPhaseStateLock, LW_EXCLUSIVE));
 
 	if (!fromdisk)
-		Assert(prepare_start_lsn != InvalidXLogRecPtr);
+		Assert(!XLogRecPtrIsInvalid(prepare_start_lsn));
 
 	/* Already processed? */
 	if (TransactionIdDidCommit(XidFromFullTransactionId(fxid)) ||
-- 
2.34.1

v1-0003-make-use-of-XLogRecPtrIsInvalid-in-xlog.c.patchtext/x-diff; charset=us-asciiDownload
From 8997aba7245bdf8b5009228844599a839dd82861 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Tue, 28 Oct 2025 05:47:29 +0000
Subject: [PATCH v1 03/20] make use of XLogRecPtrIsInvalid in xlog.c

---
 src/backend/access/transam/xlog.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)
 100.0% src/backend/access/transam/

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index eceab341255..176bebf1ea9 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -847,7 +847,7 @@ XLogInsertRecord(XLogRecData *rdata,
 
 		if (doPageWrites &&
 			(!prevDoPageWrites ||
-			 (fpw_lsn != InvalidXLogRecPtr && fpw_lsn <= RedoRecPtr)))
+			 (!XLogRecPtrIsInvalid(fpw_lsn) && fpw_lsn <= RedoRecPtr)))
 		{
 			/*
 			 * Oops, some buffer now needs to be backed up that the caller
@@ -881,7 +881,7 @@ XLogInsertRecord(XLogRecData *rdata,
 		 * Those checks are only needed for records that can contain buffer
 		 * references, and an XLOG_SWITCH record never does.
 		 */
-		Assert(fpw_lsn == InvalidXLogRecPtr);
+		Assert(XLogRecPtrIsInvalid(fpw_lsn));
 		WALInsertLockAcquireExclusive();
 		inserted = ReserveXLogSwitch(&StartPos, &EndPos, &rechdr->xl_prev);
 	}
@@ -896,7 +896,7 @@ XLogInsertRecord(XLogRecData *rdata,
 		 * not check RedoRecPtr before inserting the record; we just need to
 		 * update it afterwards.
 		 */
-		Assert(fpw_lsn == InvalidXLogRecPtr);
+		Assert(XLogRecPtrIsInvalid(fpw_lsn));
 		WALInsertLockAcquireExclusive();
 		ReserveXLogInsertLocation(rechdr->xl_tot_len, &StartPos, &EndPos,
 								  &rechdr->xl_prev);
@@ -1600,7 +1600,7 @@ WaitXLogInsertionsToFinish(XLogRecPtr upto)
 			 */
 		} while (insertingat < upto);
 
-		if (insertingat != InvalidXLogRecPtr && insertingat < finishedUpto)
+		if (!XLogRecPtrIsInvalid(insertingat) && insertingat < finishedUpto)
 			finishedUpto = insertingat;
 	}
 
@@ -7354,7 +7354,7 @@ CreateCheckPoint(int flags)
 	 * Update the average distance between checkpoints if the prior checkpoint
 	 * exists.
 	 */
-	if (PriorRedoPtr != InvalidXLogRecPtr)
+	if (!XLogRecPtrIsInvalid(PriorRedoPtr))
 		UpdateCheckPointDistanceEstimate(RedoRecPtr - PriorRedoPtr);
 
 	INJECTION_POINT("checkpoint-before-old-wal-removal", NULL);
@@ -7802,7 +7802,7 @@ CreateRestartPoint(int flags)
 	 * Update the average distance between checkpoints/restartpoints if the
 	 * prior checkpoint exists.
 	 */
-	if (PriorRedoPtr != InvalidXLogRecPtr)
+	if (!XLogRecPtrIsInvalid(PriorRedoPtr))
 		UpdateCheckPointDistanceEstimate(RedoRecPtr - PriorRedoPtr);
 
 	/*
@@ -8009,7 +8009,7 @@ KeepLogSeg(XLogRecPtr recptr, XLogSegNo *logSegNo)
 
 	/* Calculate how many segments are kept by slots. */
 	keep = XLogGetReplicationSlotMinimumLSN();
-	if (keep != InvalidXLogRecPtr && keep < recptr)
+	if (!XLogRecPtrIsInvalid(keep) && keep < recptr)
 	{
 		XLByteToSeg(keep, segno, wal_segment_size);
 
@@ -8036,7 +8036,7 @@ KeepLogSeg(XLogRecPtr recptr, XLogSegNo *logSegNo)
 	 * summarized.
 	 */
 	keep = GetOldestUnsummarizedLSN(NULL, NULL);
-	if (keep != InvalidXLogRecPtr)
+	if (!XLogRecPtrIsInvalid(keep))
 	{
 		XLogSegNo	unsummarized_segno;
 
@@ -8594,7 +8594,7 @@ xlog_redo(XLogReaderState *record)
 			LocalMinRecoveryPoint = ControlFile->minRecoveryPoint;
 			LocalMinRecoveryPointTLI = ControlFile->minRecoveryPointTLI;
 		}
-		if (LocalMinRecoveryPoint != InvalidXLogRecPtr && LocalMinRecoveryPoint < lsn)
+		if (!XLogRecPtrIsInvalid(LocalMinRecoveryPoint) && LocalMinRecoveryPoint < lsn)
 		{
 			TimeLineID	replayTLI;
 
-- 
2.34.1

v1-0004-make-use-of-XLogRecPtrIsInvalid-in-xloginsert.c.patchtext/x-diff; charset=us-asciiDownload
From c4c5601e2110a46928726bb1b120486862a49a24 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Tue, 28 Oct 2025 05:53:48 +0000
Subject: [PATCH v1 04/20] make use of XLogRecPtrIsInvalid in xloginsert.c

---
 src/backend/access/transam/xloginsert.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
 100.0% src/backend/access/transam/

diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c
index 496e0fa4ac6..9c873393c1b 100644
--- a/src/backend/access/transam/xloginsert.c
+++ b/src/backend/access/transam/xloginsert.c
@@ -523,7 +523,7 @@ XLogInsert(RmgrId rmid, uint8 info)
 
 		EndPos = XLogInsertRecord(rdt, fpw_lsn, curinsert_flags, num_fpi,
 								  topxid_included);
-	} while (EndPos == InvalidXLogRecPtr);
+	} while (XLogRecPtrIsInvalid(EndPos));
 
 	XLogResetInsertion();
 
@@ -633,7 +633,7 @@ XLogRecordAssemble(RmgrId rmid, uint8 info,
 			needs_backup = (page_lsn <= RedoRecPtr);
 			if (!needs_backup)
 			{
-				if (*fpw_lsn == InvalidXLogRecPtr || page_lsn < *fpw_lsn)
+				if (XLogRecPtrIsInvalid(*fpw_lsn) || page_lsn < *fpw_lsn)
 					*fpw_lsn = page_lsn;
 			}
 		}
-- 
2.34.1

v1-0005-make-use-of-XLogRecPtrIsInvalid-in-xlogreader.c.patchtext/x-diff; charset=us-asciiDownload
From 2fa79374dc2be16764360093cb0d3ff3660a2a4d Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Tue, 28 Oct 2025 05:55:21 +0000
Subject: [PATCH v1 05/20] make use of XLogRecPtrIsInvalid in xlogreader.c

---
 src/backend/access/transam/xlogreader.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
 100.0% src/backend/access/transam/

diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index dcc8d4f9c1b..5e3ebdeacc3 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -558,7 +558,7 @@ XLogDecodeNextRecord(XLogReaderState *state, bool nonblocking)
 
 	RecPtr = state->NextRecPtr;
 
-	if (state->DecodeRecPtr != InvalidXLogRecPtr)
+	if (!XLogRecPtrIsInvalid(state->DecodeRecPtr))
 	{
 		/* read the record after the one we just read */
 
-- 
2.34.1

v1-0006-make-use-of-XLogRecPtrIsInvalid-in-xlogrecovery.c.patchtext/x-diff; charset=us-asciiDownload
From 172d98bcca7b733f8e5f7e1e0266029cedf0aede Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Tue, 28 Oct 2025 05:58:08 +0000
Subject: [PATCH v1 06/20] make use of XLogRecPtrIsInvalid in xlogrecovery.c

---
 src/backend/access/transam/xlogrecovery.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
 100.0% src/backend/access/transam/

diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index 3e3c4da01a2..eb999584aa9 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -757,9 +757,9 @@ InitWalRecovery(ControlFileData *ControlFile, bool *wasShutdown_ptr,
 		 * end-of-backup record), and we can enter archive recovery directly.
 		 */
 		if (ArchiveRecoveryRequested &&
-			(ControlFile->minRecoveryPoint != InvalidXLogRecPtr ||
+			(!XLogRecPtrIsInvalid(ControlFile->minRecoveryPoint) ||
 			 ControlFile->backupEndRequired ||
-			 ControlFile->backupEndPoint != InvalidXLogRecPtr ||
+			 !XLogRecPtrIsInvalid(ControlFile->backupEndPoint) ||
 			 ControlFile->state == DB_SHUTDOWNED))
 		{
 			InArchiveRecovery = true;
@@ -3151,7 +3151,7 @@ ReadRecord(XLogPrefetcher *xlogprefetcher, int emode,
 	/* Pass through parameters to XLogPageRead */
 	private->fetching_ckpt = fetching_ckpt;
 	private->emode = emode;
-	private->randAccess = (xlogreader->ReadRecPtr == InvalidXLogRecPtr);
+	private->randAccess = (XLogRecPtrIsInvalid(xlogreader->ReadRecPtr));
 	private->replayTLI = replayTLI;
 
 	/* This is the first attempt to read this page. */
@@ -4336,7 +4336,7 @@ XLogFileReadAnyTLI(XLogSegNo segno, XLogSource source)
 		 * Skip scanning the timeline ID that the logfile segment to read
 		 * doesn't belong to
 		 */
-		if (hent->begin != InvalidXLogRecPtr)
+		if (!XLogRecPtrIsInvalid(hent->begin))
 		{
 			XLogSegNo	beginseg = 0;
 
-- 
2.34.1

v1-0007-make-use-of-XLogRecPtrIsInvalid-in-xlogutils.c.patchtext/x-diff; charset=us-asciiDownload
From f39f1db6f737bd155a804ec8f1859ab781dd83c4 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Tue, 28 Oct 2025 06:00:26 +0000
Subject: [PATCH v1 07/20] make use of XLogRecPtrIsInvalid in xlogutils.c

---
 src/backend/access/transam/xlogutils.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
 100.0% src/backend/access/transam/

diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c
index 38176d9688e..9e8a5ac627b 100644
--- a/src/backend/access/transam/xlogutils.c
+++ b/src/backend/access/transam/xlogutils.c
@@ -710,7 +710,7 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage,
 	const XLogRecPtr lastReadPage = (state->seg.ws_segno *
 									 state->segcxt.ws_segsize + state->segoff);
 
-	Assert(wantPage != InvalidXLogRecPtr && wantPage % XLOG_BLCKSZ == 0);
+	Assert(!XLogRecPtrIsInvalid(wantPage) && wantPage % XLOG_BLCKSZ == 0);
 	Assert(wantLength <= XLOG_BLCKSZ);
 	Assert(state->readLen == 0 || state->readLen <= XLOG_BLCKSZ);
 	Assert(currTLI != 0);
@@ -741,7 +741,7 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage,
 	 */
 	if (state->currTLI == currTLI && wantPage >= lastReadPage)
 	{
-		Assert(state->currTLIValidUntil == InvalidXLogRecPtr);
+		Assert(XLogRecPtrIsInvalid(state->currTLIValidUntil));
 		return;
 	}
 
@@ -750,7 +750,7 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage,
 	 * timeline and the timeline we're reading from is valid until the end of
 	 * the current segment we can just keep reading.
 	 */
-	if (state->currTLIValidUntil != InvalidXLogRecPtr &&
+	if (!XLogRecPtrIsInvalid(state->currTLIValidUntil) &&
 		state->currTLI != currTLI &&
 		state->currTLI != 0 &&
 		((wantPage + wantLength) / state->segcxt.ws_segsize) <
@@ -790,7 +790,7 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage,
 		state->currTLIValidUntil = tliSwitchPoint(state->currTLI, timelineHistory,
 												  &state->nextTLI);
 
-		Assert(state->currTLIValidUntil == InvalidXLogRecPtr ||
+		Assert(XLogRecPtrIsInvalid(state->currTLIValidUntil) ||
 			   wantPage + wantLength < state->currTLIValidUntil);
 
 		list_free_deep(timelineHistory);
-- 
2.34.1

v1-0008-make-use-of-XLogRecPtrIsInvalid-in-pg_subscriptio.patchtext/x-diff; charset=us-asciiDownload
From 85bc1c838d16db2fc7d097868a85a93a8e992eeb Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Tue, 28 Oct 2025 06:01:56 +0000
Subject: [PATCH v1 08/20] make use of XLogRecPtrIsInvalid in pg_subscription.c

---
 src/backend/catalog/pg_subscription.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
 100.0% src/backend/catalog/

diff --git a/src/backend/catalog/pg_subscription.c b/src/backend/catalog/pg_subscription.c
index 15b233a37d8..c3ecd717de0 100644
--- a/src/backend/catalog/pg_subscription.c
+++ b/src/backend/catalog/pg_subscription.c
@@ -293,7 +293,7 @@ AddSubscriptionRelState(Oid subid, Oid relid, char state,
 	values[Anum_pg_subscription_rel_srsubid - 1] = ObjectIdGetDatum(subid);
 	values[Anum_pg_subscription_rel_srrelid - 1] = ObjectIdGetDatum(relid);
 	values[Anum_pg_subscription_rel_srsubstate - 1] = CharGetDatum(state);
-	if (sublsn != InvalidXLogRecPtr)
+	if (!XLogRecPtrIsInvalid(sublsn))
 		values[Anum_pg_subscription_rel_srsublsn - 1] = LSNGetDatum(sublsn);
 	else
 		nulls[Anum_pg_subscription_rel_srsublsn - 1] = true;
@@ -366,7 +366,7 @@ UpdateSubscriptionRelState(Oid subid, Oid relid, char state,
 	values[Anum_pg_subscription_rel_srsubstate - 1] = CharGetDatum(state);
 
 	replaces[Anum_pg_subscription_rel_srsublsn - 1] = true;
-	if (sublsn != InvalidXLogRecPtr)
+	if (!XLogRecPtrIsInvalid(sublsn))
 		values[Anum_pg_subscription_rel_srsublsn - 1] = LSNGetDatum(sublsn);
 	else
 		nulls[Anum_pg_subscription_rel_srsublsn - 1] = true;
-- 
2.34.1

v1-0009-make-use-of-XLogRecPtrIsInvalid-in-logical.c.patchtext/x-diff; charset=us-asciiDownload
From 66b5a37a26613d830ead892411466329f5d53b6f Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Tue, 28 Oct 2025 06:08:37 +0000
Subject: [PATCH v1 09/20] make use of XLogRecPtrIsInvalid in logical.c

---
 src/backend/replication/logical/logical.c | 30 +++++++++++------------
 1 file changed, 15 insertions(+), 15 deletions(-)
 100.0% src/backend/replication/logical/

diff --git a/src/backend/replication/logical/logical.c b/src/backend/replication/logical/logical.c
index 93ed2eb368e..295e83ad9d6 100644
--- a/src/backend/replication/logical/logical.c
+++ b/src/backend/replication/logical/logical.c
@@ -546,9 +546,9 @@ CreateDecodingContext(XLogRecPtr start_lsn,
 
 	/* slot must be valid to allow decoding */
 	Assert(slot->data.invalidated == RS_INVAL_NONE);
-	Assert(slot->data.restart_lsn != InvalidXLogRecPtr);
+	Assert(!XLogRecPtrIsInvalid(slot->data.restart_lsn));
 
-	if (start_lsn == InvalidXLogRecPtr)
+	if (XLogRecPtrIsInvalid(start_lsn))
 	{
 		/* continue from last position */
 		start_lsn = slot->data.confirmed_flush;
@@ -757,7 +757,7 @@ output_plugin_error_callback(void *arg)
 	LogicalErrorCallbackState *state = (LogicalErrorCallbackState *) arg;
 
 	/* not all callbacks have an associated LSN  */
-	if (state->report_location != InvalidXLogRecPtr)
+	if (!XLogRecPtrIsInvalid(state->report_location))
 		errcontext("slot \"%s\", output plugin \"%s\", in the %s callback, associated LSN %X/%08X",
 				   NameStr(state->ctx->slot->data.name),
 				   NameStr(state->ctx->slot->data.plugin),
@@ -1711,7 +1711,7 @@ LogicalIncreaseXminForSlot(XLogRecPtr current_lsn, TransactionId xmin)
 	 * Only increase if the previous values have been applied, otherwise we
 	 * might never end up updating if the receiver acks too slowly.
 	 */
-	else if (slot->candidate_xmin_lsn == InvalidXLogRecPtr)
+	else if (XLogRecPtrIsInvalid(slot->candidate_xmin_lsn))
 	{
 		slot->candidate_catalog_xmin = xmin;
 		slot->candidate_xmin_lsn = current_lsn;
@@ -1749,8 +1749,8 @@ LogicalIncreaseRestartDecodingForSlot(XLogRecPtr current_lsn, XLogRecPtr restart
 	slot = MyReplicationSlot;
 
 	Assert(slot != NULL);
-	Assert(restart_lsn != InvalidXLogRecPtr);
-	Assert(current_lsn != InvalidXLogRecPtr);
+	Assert(!XLogRecPtrIsInvalid(restart_lsn));
+	Assert(!XLogRecPtrIsInvalid(current_lsn));
 
 	SpinLockAcquire(&slot->mutex);
 
@@ -1779,7 +1779,7 @@ LogicalIncreaseRestartDecodingForSlot(XLogRecPtr current_lsn, XLogRecPtr restart
 	 * might never end up updating if the receiver acks too slowly. A missed
 	 * value here will just cause some extra effort after reconnecting.
 	 */
-	else if (slot->candidate_restart_valid == InvalidXLogRecPtr)
+	else if (XLogRecPtrIsInvalid(slot->candidate_restart_valid))
 	{
 		slot->candidate_restart_valid = current_lsn;
 		slot->candidate_restart_lsn = restart_lsn;
@@ -1819,11 +1819,11 @@ LogicalIncreaseRestartDecodingForSlot(XLogRecPtr current_lsn, XLogRecPtr restart
 void
 LogicalConfirmReceivedLocation(XLogRecPtr lsn)
 {
-	Assert(lsn != InvalidXLogRecPtr);
+	Assert(!XLogRecPtrIsInvalid(lsn));
 
 	/* Do an unlocked check for candidate_lsn first. */
-	if (MyReplicationSlot->candidate_xmin_lsn != InvalidXLogRecPtr ||
-		MyReplicationSlot->candidate_restart_valid != InvalidXLogRecPtr)
+	if (!XLogRecPtrIsInvalid(MyReplicationSlot->candidate_xmin_lsn) ||
+		!XLogRecPtrIsInvalid(MyReplicationSlot->candidate_restart_valid))
 	{
 		bool		updated_xmin = false;
 		bool		updated_restart = false;
@@ -1849,7 +1849,7 @@ LogicalConfirmReceivedLocation(XLogRecPtr lsn)
 			MyReplicationSlot->data.confirmed_flush = lsn;
 
 		/* if we're past the location required for bumping xmin, do so */
-		if (MyReplicationSlot->candidate_xmin_lsn != InvalidXLogRecPtr &&
+		if (!XLogRecPtrIsInvalid(MyReplicationSlot->candidate_xmin_lsn) &&
 			MyReplicationSlot->candidate_xmin_lsn <= lsn)
 		{
 			/*
@@ -1871,10 +1871,10 @@ LogicalConfirmReceivedLocation(XLogRecPtr lsn)
 			}
 		}
 
-		if (MyReplicationSlot->candidate_restart_valid != InvalidXLogRecPtr &&
+		if (!XLogRecPtrIsInvalid(MyReplicationSlot->candidate_restart_valid) &&
 			MyReplicationSlot->candidate_restart_valid <= lsn)
 		{
-			Assert(MyReplicationSlot->candidate_restart_lsn != InvalidXLogRecPtr);
+			Assert(!XLogRecPtrIsInvalid(MyReplicationSlot->candidate_restart_lsn));
 
 			MyReplicationSlot->data.restart_lsn = MyReplicationSlot->candidate_restart_lsn;
 			MyReplicationSlot->candidate_restart_lsn = InvalidXLogRecPtr;
@@ -2089,7 +2089,7 @@ LogicalSlotAdvanceAndCheckSnapState(XLogRecPtr moveto,
 	ResourceOwner old_resowner PG_USED_FOR_ASSERTS_ONLY = CurrentResourceOwner;
 	XLogRecPtr	retlsn;
 
-	Assert(moveto != InvalidXLogRecPtr);
+	Assert(!XLogRecPtrIsInvalid(moveto));
 
 	if (found_consistent_snapshot)
 		*found_consistent_snapshot = false;
@@ -2163,7 +2163,7 @@ LogicalSlotAdvanceAndCheckSnapState(XLogRecPtr moveto,
 		if (found_consistent_snapshot && DecodingContextReady(ctx))
 			*found_consistent_snapshot = true;
 
-		if (ctx->reader->EndRecPtr != InvalidXLogRecPtr)
+		if (!XLogRecPtrIsInvalid(ctx->reader->EndRecPtr))
 		{
 			LogicalConfirmReceivedLocation(moveto);
 
-- 
2.34.1

v1-0010-make-use-of-XLogRecPtrIsInvalid-in-logicalfuncs.c.patchtext/x-diff; charset=us-asciiDownload
From c93a6925615fe4384e6c85941c28198e4a66c10e Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Tue, 28 Oct 2025 06:10:16 +0000
Subject: [PATCH v1 10/20] make use of XLogRecPtrIsInvalid in logicalfuncs.c

---
 src/backend/replication/logical/logicalfuncs.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
 100.0% src/backend/replication/logical/

diff --git a/src/backend/replication/logical/logicalfuncs.c b/src/backend/replication/logical/logicalfuncs.c
index 25f890ddeed..4d1e7a55d6d 100644
--- a/src/backend/replication/logical/logicalfuncs.c
+++ b/src/backend/replication/logical/logicalfuncs.c
@@ -276,7 +276,7 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin
 			}
 
 			/* check limits */
-			if (upto_lsn != InvalidXLogRecPtr &&
+			if (!XLogRecPtrIsInvalid(upto_lsn) &&
 				upto_lsn <= ctx->reader->EndRecPtr)
 				break;
 			if (upto_nchanges != 0 &&
@@ -289,7 +289,7 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin
 		 * Next time, start where we left off. (Hunting things, the family
 		 * business..)
 		 */
-		if (ctx->reader->EndRecPtr != InvalidXLogRecPtr && confirm)
+		if (!XLogRecPtrIsInvalid(ctx->reader->EndRecPtr) && confirm)
 		{
 			LogicalConfirmReceivedLocation(ctx->reader->EndRecPtr);
 
-- 
2.34.1

v1-0011-make-use-of-XLogRecPtrIsInvalid-in-origin.c.patchtext/x-diff; charset=us-asciiDownload
From 0eeb8b4ad8288c2000e6478b0121e17c8f7596a7 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Tue, 28 Oct 2025 06:14:38 +0000
Subject: [PATCH v1 11/20] make use of XLogRecPtrIsInvalid in origin.c

---
 src/backend/replication/logical/origin.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)
 100.0% src/backend/replication/logical/

diff --git a/src/backend/replication/logical/origin.c b/src/backend/replication/logical/origin.c
index bcd5d9aad62..3573a0cedca 100644
--- a/src/backend/replication/logical/origin.c
+++ b/src/backend/replication/logical/origin.c
@@ -984,8 +984,8 @@ replorigin_advance(RepOriginId node,
 		/* initialize new slot */
 		LWLockAcquire(&free_state->lock, LW_EXCLUSIVE);
 		replication_state = free_state;
-		Assert(replication_state->remote_lsn == InvalidXLogRecPtr);
-		Assert(replication_state->local_lsn == InvalidXLogRecPtr);
+		Assert(XLogRecPtrIsInvalid(replication_state->remote_lsn));
+		Assert(XLogRecPtrIsInvalid(replication_state->local_lsn));
 		replication_state->roident = node;
 	}
 
@@ -1020,7 +1020,7 @@ replorigin_advance(RepOriginId node,
 	 */
 	if (go_backward || replication_state->remote_lsn < remote_commit)
 		replication_state->remote_lsn = remote_commit;
-	if (local_commit != InvalidXLogRecPtr &&
+	if (!XLogRecPtrIsInvalid(local_commit) &&
 		(go_backward || replication_state->local_lsn < local_commit))
 		replication_state->local_lsn = local_commit;
 	LWLockRelease(&replication_state->lock);
@@ -1064,7 +1064,7 @@ replorigin_get_progress(RepOriginId node, bool flush)
 
 	LWLockRelease(ReplicationOriginLock);
 
-	if (flush && local_lsn != InvalidXLogRecPtr)
+	if (flush && !XLogRecPtrIsInvalid(local_lsn))
 		XLogFlush(local_lsn);
 
 	return remote_lsn;
@@ -1197,8 +1197,8 @@ replorigin_session_setup(RepOriginId node, int acquired_by)
 
 		/* initialize new slot */
 		session_replication_state = &replication_states[free_slot];
-		Assert(session_replication_state->remote_lsn == InvalidXLogRecPtr);
-		Assert(session_replication_state->local_lsn == InvalidXLogRecPtr);
+		Assert(XLogRecPtrIsInvalid(session_replication_state->remote_lsn));
+		Assert(XLogRecPtrIsInvalid(session_replication_state->local_lsn));
 		session_replication_state->roident = node;
 	}
 
@@ -1282,7 +1282,7 @@ replorigin_session_get_progress(bool flush)
 	local_lsn = session_replication_state->local_lsn;
 	LWLockRelease(&session_replication_state->lock);
 
-	if (flush && local_lsn != InvalidXLogRecPtr)
+	if (flush && !XLogRecPtrIsInvalid(local_lsn))
 		XLogFlush(local_lsn);
 
 	return remote_lsn;
@@ -1454,7 +1454,7 @@ pg_replication_origin_session_progress(PG_FUNCTION_ARGS)
 
 	remote_lsn = replorigin_session_get_progress(flush);
 
-	if (remote_lsn == InvalidXLogRecPtr)
+	if (XLogRecPtrIsInvalid(remote_lsn))
 		PG_RETURN_NULL();
 
 	PG_RETURN_LSN(remote_lsn);
@@ -1543,7 +1543,7 @@ pg_replication_origin_progress(PG_FUNCTION_ARGS)
 
 	remote_lsn = replorigin_get_progress(roident, flush);
 
-	if (remote_lsn == InvalidXLogRecPtr)
+	if (XLogRecPtrIsInvalid(remote_lsn))
 		PG_RETURN_NULL();
 
 	PG_RETURN_LSN(remote_lsn);
-- 
2.34.1

v1-0012-make-use-of-XLogRecPtrIsInvalid-in-proto.c.patchtext/x-diff; charset=us-asciiDownload
From 8265d4a2d4a06bf27727796497100bb928c7cd18 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Tue, 28 Oct 2025 06:20:44 +0000
Subject: [PATCH v1 12/20] make use of XLogRecPtrIsInvalid in proto.c

---
 src/backend/replication/logical/proto.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)
 100.0% src/backend/replication/logical/

diff --git a/src/backend/replication/logical/proto.c b/src/backend/replication/logical/proto.c
index ed62888764c..28f0e2e45f1 100644
--- a/src/backend/replication/logical/proto.c
+++ b/src/backend/replication/logical/proto.c
@@ -64,7 +64,7 @@ logicalrep_read_begin(StringInfo in, LogicalRepBeginData *begin_data)
 {
 	/* read fields */
 	begin_data->final_lsn = pq_getmsgint64(in);
-	if (begin_data->final_lsn == InvalidXLogRecPtr)
+	if (XLogRecPtrIsInvalid(begin_data->final_lsn))
 		elog(ERROR, "final_lsn not set in begin message");
 	begin_data->committime = pq_getmsgint64(in);
 	begin_data->xid = pq_getmsgint(in, 4);
@@ -135,10 +135,10 @@ logicalrep_read_begin_prepare(StringInfo in, LogicalRepPreparedTxnData *begin_da
 {
 	/* read fields */
 	begin_data->prepare_lsn = pq_getmsgint64(in);
-	if (begin_data->prepare_lsn == InvalidXLogRecPtr)
+	if (XLogRecPtrIsInvalid(begin_data->prepare_lsn))
 		elog(ERROR, "prepare_lsn not set in begin prepare message");
 	begin_data->end_lsn = pq_getmsgint64(in);
-	if (begin_data->end_lsn == InvalidXLogRecPtr)
+	if (XLogRecPtrIsInvalid(begin_data->end_lsn))
 		elog(ERROR, "end_lsn not set in begin prepare message");
 	begin_data->prepare_time = pq_getmsgint64(in);
 	begin_data->xid = pq_getmsgint(in, 4);
@@ -207,10 +207,10 @@ logicalrep_read_prepare_common(StringInfo in, char *msgtype,
 
 	/* read fields */
 	prepare_data->prepare_lsn = pq_getmsgint64(in);
-	if (prepare_data->prepare_lsn == InvalidXLogRecPtr)
+	if (XLogRecPtrIsInvalid(prepare_data->prepare_lsn))
 		elog(ERROR, "prepare_lsn is not set in %s message", msgtype);
 	prepare_data->end_lsn = pq_getmsgint64(in);
-	if (prepare_data->end_lsn == InvalidXLogRecPtr)
+	if (XLogRecPtrIsInvalid(prepare_data->end_lsn))
 		elog(ERROR, "end_lsn is not set in %s message", msgtype);
 	prepare_data->prepare_time = pq_getmsgint64(in);
 	prepare_data->xid = pq_getmsgint(in, 4);
@@ -274,10 +274,10 @@ logicalrep_read_commit_prepared(StringInfo in, LogicalRepCommitPreparedTxnData *
 
 	/* read fields */
 	prepare_data->commit_lsn = pq_getmsgint64(in);
-	if (prepare_data->commit_lsn == InvalidXLogRecPtr)
+	if (XLogRecPtrIsInvalid(prepare_data->commit_lsn))
 		elog(ERROR, "commit_lsn is not set in commit prepared message");
 	prepare_data->end_lsn = pq_getmsgint64(in);
-	if (prepare_data->end_lsn == InvalidXLogRecPtr)
+	if (XLogRecPtrIsInvalid(prepare_data->end_lsn))
 		elog(ERROR, "end_lsn is not set in commit prepared message");
 	prepare_data->commit_time = pq_getmsgint64(in);
 	prepare_data->xid = pq_getmsgint(in, 4);
@@ -333,10 +333,10 @@ logicalrep_read_rollback_prepared(StringInfo in,
 
 	/* read fields */
 	rollback_data->prepare_end_lsn = pq_getmsgint64(in);
-	if (rollback_data->prepare_end_lsn == InvalidXLogRecPtr)
+	if (XLogRecPtrIsInvalid(rollback_data->prepare_end_lsn))
 		elog(ERROR, "prepare_end_lsn is not set in rollback prepared message");
 	rollback_data->rollback_end_lsn = pq_getmsgint64(in);
-	if (rollback_data->rollback_end_lsn == InvalidXLogRecPtr)
+	if (XLogRecPtrIsInvalid(rollback_data->rollback_end_lsn))
 		elog(ERROR, "rollback_end_lsn is not set in rollback prepared message");
 	rollback_data->prepare_time = pq_getmsgint64(in);
 	rollback_data->rollback_time = pq_getmsgint64(in);
-- 
2.34.1

v1-0013-make-use-of-XLogRecPtrIsInvalid-in-reorderbuffer..patchtext/x-diff; charset=us-asciiDownload
From 727e6a69fc0a94942be9f90074aa886347c0de26 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Tue, 28 Oct 2025 06:27:43 +0000
Subject: [PATCH v1 13/20] make use of XLogRecPtrIsInvalid in reorderbuffer.c

---
 .../replication/logical/reorderbuffer.c       | 38 +++++++++----------
 1 file changed, 19 insertions(+), 19 deletions(-)
 100.0% src/backend/replication/logical/

diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c
index b57aef9916d..316f81c73e3 100644
--- a/src/backend/replication/logical/reorderbuffer.c
+++ b/src/backend/replication/logical/reorderbuffer.c
@@ -701,7 +701,7 @@ ReorderBufferTXNByXid(ReorderBuffer *rb, TransactionId xid, bool create,
 	{
 		/* initialize the new entry, if creation was requested */
 		Assert(ent != NULL);
-		Assert(lsn != InvalidXLogRecPtr);
+		Assert(!XLogRecPtrIsInvalid(lsn));
 
 		ent->txn = ReorderBufferAllocTXN(rb);
 		ent->txn->xid = xid;
@@ -849,7 +849,7 @@ ReorderBufferQueueChange(ReorderBuffer *rb, TransactionId xid, XLogRecPtr lsn,
 	change->lsn = lsn;
 	change->txn = txn;
 
-	Assert(InvalidXLogRecPtr != lsn);
+	Assert(!XLogRecPtrIsInvalid(lsn));
 	dlist_push_tail(&txn->changes, &change->node);
 	txn->nentries++;
 	txn->nentries_mem++;
@@ -966,14 +966,14 @@ AssertTXNLsnOrder(ReorderBuffer *rb)
 													iter.cur);
 
 		/* start LSN must be set */
-		Assert(cur_txn->first_lsn != InvalidXLogRecPtr);
+		Assert(!XLogRecPtrIsInvalid(cur_txn->first_lsn));
 
 		/* If there is an end LSN, it must be higher than start LSN */
-		if (cur_txn->end_lsn != InvalidXLogRecPtr)
+		if (!XLogRecPtrIsInvalid(cur_txn->end_lsn))
 			Assert(cur_txn->first_lsn <= cur_txn->end_lsn);
 
 		/* Current initial LSN must be strictly higher than previous */
-		if (prev_first_lsn != InvalidXLogRecPtr)
+		if (!XLogRecPtrIsInvalid(prev_first_lsn))
 			Assert(prev_first_lsn < cur_txn->first_lsn);
 
 		/* known-as-subtxn txns must not be listed */
@@ -990,10 +990,10 @@ AssertTXNLsnOrder(ReorderBuffer *rb)
 
 		/* base snapshot (and its LSN) must be set */
 		Assert(cur_txn->base_snapshot != NULL);
-		Assert(cur_txn->base_snapshot_lsn != InvalidXLogRecPtr);
+		Assert(!XLogRecPtrIsInvalid(cur_txn->base_snapshot_lsn));
 
 		/* current LSN must be strictly higher than previous */
-		if (prev_base_snap_lsn != InvalidXLogRecPtr)
+		if (!XLogRecPtrIsInvalid(prev_base_snap_lsn))
 			Assert(prev_base_snap_lsn < cur_txn->base_snapshot_lsn);
 
 		/* known-as-subtxn txns must not be listed */
@@ -1022,11 +1022,11 @@ AssertChangeLsnOrder(ReorderBufferTXN *txn)
 
 		cur_change = dlist_container(ReorderBufferChange, node, iter.cur);
 
-		Assert(txn->first_lsn != InvalidXLogRecPtr);
-		Assert(cur_change->lsn != InvalidXLogRecPtr);
+		Assert(!XLogRecPtrIsInvalid(txn->first_lsn));
+		Assert(!XLogRecPtrIsInvalid(cur_change->lsn));
 		Assert(txn->first_lsn <= cur_change->lsn);
 
-		if (txn->end_lsn != InvalidXLogRecPtr)
+		if (!XLogRecPtrIsInvalid(txn->end_lsn))
 			Assert(cur_change->lsn <= txn->end_lsn);
 
 		Assert(prev_lsn <= cur_change->lsn);
@@ -1053,7 +1053,7 @@ ReorderBufferGetOldestTXN(ReorderBuffer *rb)
 	txn = dlist_head_element(ReorderBufferTXN, node, &rb->toplevel_by_lsn);
 
 	Assert(!rbtxn_is_known_subxact(txn));
-	Assert(txn->first_lsn != InvalidXLogRecPtr);
+	Assert(!XLogRecPtrIsInvalid(txn->first_lsn));
 	return txn;
 }
 
@@ -2276,7 +2276,7 @@ ReorderBufferProcessTXN(ReorderBuffer *rb, ReorderBufferTXN *txn,
 			 * We can't call start stream callback before processing first
 			 * change.
 			 */
-			if (prev_lsn == InvalidXLogRecPtr)
+			if (XLogRecPtrIsInvalid(prev_lsn))
 			{
 				if (streaming)
 				{
@@ -2291,7 +2291,7 @@ ReorderBufferProcessTXN(ReorderBuffer *rb, ReorderBufferTXN *txn,
 			 * subtransactions. The changes may have the same LSN due to
 			 * MULTI_INSERT xlog records.
 			 */
-			Assert(prev_lsn == InvalidXLogRecPtr || prev_lsn <= change->lsn);
+			Assert(XLogRecPtrIsInvalid(prev_lsn) || prev_lsn <= change->lsn);
 
 			prev_lsn = change->lsn;
 
@@ -2975,7 +2975,7 @@ ReorderBufferPrepare(ReorderBuffer *rb, TransactionId xid,
 	 * have been updated in it by now.
 	 */
 	Assert((txn->txn_flags & RBTXN_PREPARE_STATUS_MASK) == RBTXN_IS_PREPARED);
-	Assert(txn->final_lsn != InvalidXLogRecPtr);
+	Assert(!XLogRecPtrIsInvalid(txn->final_lsn));
 
 	txn->gid = pstrdup(gid);
 
@@ -3041,7 +3041,7 @@ ReorderBufferFinishPrepared(ReorderBuffer *rb, TransactionId xid,
 		 */
 		Assert((txn->txn_flags & RBTXN_PREPARE_STATUS_MASK) ==
 			   (RBTXN_IS_PREPARED | RBTXN_SKIPPED_PREPARE));
-		Assert(txn->final_lsn != InvalidXLogRecPtr);
+		Assert(!XLogRecPtrIsInvalid(txn->final_lsn));
 
 		/*
 		 * By this time the txn has the prepare record information and it is
@@ -4552,8 +4552,8 @@ ReorderBufferRestoreChanges(ReorderBuffer *rb, ReorderBufferTXN *txn,
 	dlist_mutable_iter cleanup_iter;
 	File	   *fd = &file->vfd;
 
-	Assert(txn->first_lsn != InvalidXLogRecPtr);
-	Assert(txn->final_lsn != InvalidXLogRecPtr);
+	Assert(!XLogRecPtrIsInvalid(txn->first_lsn));
+	Assert(!XLogRecPtrIsInvalid(txn->final_lsn));
 
 	/* free current entries, so we have memory for more */
 	dlist_foreach_modify(cleanup_iter, &txn->changes)
@@ -4860,8 +4860,8 @@ ReorderBufferRestoreCleanup(ReorderBuffer *rb, ReorderBufferTXN *txn)
 	XLogSegNo	cur;
 	XLogSegNo	last;
 
-	Assert(txn->first_lsn != InvalidXLogRecPtr);
-	Assert(txn->final_lsn != InvalidXLogRecPtr);
+	Assert(!XLogRecPtrIsInvalid(txn->first_lsn));
+	Assert(!XLogRecPtrIsInvalid(txn->final_lsn));
 
 	XLByteToSeg(txn->first_lsn, first, wal_segment_size);
 	XLByteToSeg(txn->final_lsn, last, wal_segment_size);
-- 
2.34.1

v1-0014-make-use-of-XLogRecPtrIsInvalid-in-snapbuild.c.patchtext/x-diff; charset=us-asciiDownload
From a886f2c23b3b93ab3fa3742e9e57eaee3cd896a2 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Tue, 28 Oct 2025 06:31:31 +0000
Subject: [PATCH v1 14/20] make use of XLogRecPtrIsInvalid in snapbuild.c

---
 src/backend/replication/logical/snapbuild.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)
 100.0% src/backend/replication/logical/

diff --git a/src/backend/replication/logical/snapbuild.c b/src/backend/replication/logical/snapbuild.c
index 98ddee20929..6014b423853 100644
--- a/src/backend/replication/logical/snapbuild.c
+++ b/src/backend/replication/logical/snapbuild.c
@@ -1210,7 +1210,7 @@ SnapBuildProcessRunningXacts(SnapBuild *builder, XLogRecPtr lsn, xl_running_xact
 	 * oldest ongoing txn might have started when we didn't yet serialize
 	 * anything because we hadn't reached a consistent state yet.
 	 */
-	if (txn != NULL && txn->restart_decoding_lsn != InvalidXLogRecPtr)
+	if (txn != NULL && !XLogRecPtrIsInvalid(txn->restart_decoding_lsn))
 		LogicalIncreaseRestartDecodingForSlot(lsn, txn->restart_decoding_lsn);
 
 	/*
@@ -1218,8 +1218,8 @@ SnapBuildProcessRunningXacts(SnapBuild *builder, XLogRecPtr lsn, xl_running_xact
 	 * we have one.
 	 */
 	else if (txn == NULL &&
-			 builder->reorder->current_restart_decoding_lsn != InvalidXLogRecPtr &&
-			 builder->last_serialized_snapshot != InvalidXLogRecPtr)
+			 !XLogRecPtrIsInvalid(builder->reorder->current_restart_decoding_lsn) &&
+			 !XLogRecPtrIsInvalid(builder->last_serialized_snapshot))
 		LogicalIncreaseRestartDecodingForSlot(lsn,
 											  builder->last_serialized_snapshot);
 }
@@ -1293,7 +1293,7 @@ SnapBuildFindSnapshot(SnapBuild *builder, XLogRecPtr lsn, xl_running_xacts *runn
 	 */
 	if (running->oldestRunningXid == running->nextXid)
 	{
-		if (builder->start_decoding_at == InvalidXLogRecPtr ||
+		if (XLogRecPtrIsInvalid(builder->start_decoding_at) ||
 			builder->start_decoding_at <= lsn)
 			/* can decode everything after this */
 			builder->start_decoding_at = lsn + 1;
@@ -1509,8 +1509,8 @@ SnapBuildSerialize(SnapBuild *builder, XLogRecPtr lsn)
 	struct stat stat_buf;
 	Size		sz;
 
-	Assert(lsn != InvalidXLogRecPtr);
-	Assert(builder->last_serialized_snapshot == InvalidXLogRecPtr ||
+	Assert(!XLogRecPtrIsInvalid(lsn));
+	Assert(XLogRecPtrIsInvalid(builder->last_serialized_snapshot) ||
 		   builder->last_serialized_snapshot <= lsn);
 
 	/*
@@ -2029,7 +2029,7 @@ CheckPointSnapBuild(void)
 		lsn = ((uint64) hi) << 32 | lo;
 
 		/* check whether we still need it */
-		if (lsn < cutoff || cutoff == InvalidXLogRecPtr)
+		if (lsn < cutoff || XLogRecPtrIsInvalid(cutoff))
 		{
 			elog(DEBUG1, "removing snapbuild snapshot %s", path);
 
-- 
2.34.1

v1-0015-make-use-of-XLogRecPtrIsInvalid-in-slot.c.patchtext/x-diff; charset=us-asciiDownload
From 02b68eec1227dd24a0b09f6a0771a47851ff593e Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Tue, 28 Oct 2025 06:35:43 +0000
Subject: [PATCH v1 15/20] make use of XLogRecPtrIsInvalid in slot.c

---
 src/backend/replication/slot.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)
 100.0% src/backend/replication/

diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index 1e9f4602c69..a1df3740851 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -1270,15 +1270,15 @@ ReplicationSlotsComputeRequiredLSN(void)
 		 */
 		if (persistency == RS_PERSISTENT)
 		{
-			if (last_saved_restart_lsn != InvalidXLogRecPtr &&
+			if (!XLogRecPtrIsInvalid(last_saved_restart_lsn) &&
 				restart_lsn > last_saved_restart_lsn)
 			{
 				restart_lsn = last_saved_restart_lsn;
 			}
 		}
 
-		if (restart_lsn != InvalidXLogRecPtr &&
-			(min_required == InvalidXLogRecPtr ||
+		if (!XLogRecPtrIsInvalid(restart_lsn) &&
+			(XLogRecPtrIsInvalid(min_required) ||
 			 restart_lsn < min_required))
 			min_required = restart_lsn;
 	}
@@ -1350,17 +1350,17 @@ ReplicationSlotsComputeLogicalRestartLSN(void)
 		 */
 		if (persistency == RS_PERSISTENT)
 		{
-			if (last_saved_restart_lsn != InvalidXLogRecPtr &&
+			if (!XLogRecPtrIsInvalid(last_saved_restart_lsn) &&
 				restart_lsn > last_saved_restart_lsn)
 			{
 				restart_lsn = last_saved_restart_lsn;
 			}
 		}
 
-		if (restart_lsn == InvalidXLogRecPtr)
+		if (XLogRecPtrIsInvalid(restart_lsn))
 			continue;
 
-		if (result == InvalidXLogRecPtr ||
+		if (XLogRecPtrIsInvalid(result) ||
 			restart_lsn < result)
 			result = restart_lsn;
 	}
@@ -1573,8 +1573,8 @@ ReplicationSlotReserveWal(void)
 	ReplicationSlot *slot = MyReplicationSlot;
 
 	Assert(slot != NULL);
-	Assert(slot->data.restart_lsn == InvalidXLogRecPtr);
-	Assert(slot->last_saved_restart_lsn == InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsInvalid(slot->data.restart_lsn));
+	Assert(XLogRecPtrIsInvalid(slot->last_saved_restart_lsn));
 
 	/*
 	 * The replication slot mechanism is used to prevent removal of required
@@ -1755,7 +1755,7 @@ DetermineSlotInvalidationCause(uint32 possible_causes, ReplicationSlot *s,
 
 	if (possible_causes & RS_INVAL_WAL_REMOVED)
 	{
-		if (initial_restart_lsn != InvalidXLogRecPtr &&
+		if (!XLogRecPtrIsInvalid(initial_restart_lsn) &&
 			initial_restart_lsn < oldestLSN)
 			return RS_INVAL_WAL_REMOVED;
 	}
-- 
2.34.1

v1-0016-make-use-of-XLogRecPtrIsInvalid-in-slotfuncs.c.patchtext/x-diff; charset=us-asciiDownload
From adc5faeb2046c8a22ebd8d8833c8a46cb90cb5a2 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Tue, 28 Oct 2025 06:37:29 +0000
Subject: [PATCH v1 16/20] make use of XLogRecPtrIsInvalid in slotfuncs.c

---
 src/backend/replication/slotfuncs.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
 100.0% src/backend/replication/

diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index b8f21153e7b..7a593a663e5 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -308,12 +308,12 @@ pg_get_replication_slots(PG_FUNCTION_ARGS)
 		else
 			nulls[i++] = true;
 
-		if (slot_contents.data.restart_lsn != InvalidXLogRecPtr)
+		if (!XLogRecPtrIsInvalid(slot_contents.data.restart_lsn))
 			values[i++] = LSNGetDatum(slot_contents.data.restart_lsn);
 		else
 			nulls[i++] = true;
 
-		if (slot_contents.data.confirmed_flush != InvalidXLogRecPtr)
+		if (!XLogRecPtrIsInvalid(slot_contents.data.confirmed_flush))
 			values[i++] = LSNGetDatum(slot_contents.data.confirmed_flush);
 		else
 			nulls[i++] = true;
@@ -467,7 +467,7 @@ pg_physical_replication_slot_advance(XLogRecPtr moveto)
 	XLogRecPtr	startlsn = MyReplicationSlot->data.restart_lsn;
 	XLogRecPtr	retlsn = startlsn;
 
-	Assert(moveto != InvalidXLogRecPtr);
+	Assert(!XLogRecPtrIsInvalid(moveto));
 
 	if (startlsn < moveto)
 	{
-- 
2.34.1

v1-0017-make-use-of-XLogRecPtrIsInvalid-in-walsender.c.patchtext/x-diff; charset=us-asciiDownload
From 75f70794adf53a95d32893f909c041809e249bf8 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Tue, 28 Oct 2025 06:39:26 +0000
Subject: [PATCH v1 17/20] make use of XLogRecPtrIsInvalid in walsender.c

---
 src/backend/replication/walsender.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
 100.0% src/backend/replication/

diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 548eafa7a73..622bb35e8c7 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -2397,7 +2397,7 @@ PhysicalConfirmReceivedLocation(XLogRecPtr lsn)
 	bool		changed = false;
 	ReplicationSlot *slot = MyReplicationSlot;
 
-	Assert(lsn != InvalidXLogRecPtr);
+	Assert(!XLogRecPtrIsInvalid(lsn));
 	SpinLockAcquire(&slot->mutex);
 	if (slot->data.restart_lsn != lsn)
 	{
@@ -2519,7 +2519,7 @@ ProcessStandbyReplyMessage(void)
 	/*
 	 * Advance our local xmin horizon when the client confirmed a flush.
 	 */
-	if (MyReplicationSlot && flushPtr != InvalidXLogRecPtr)
+	if (MyReplicationSlot && !XLogRecPtrIsInvalid(flushPtr))
 	{
 		if (SlotIsLogical(MyReplicationSlot))
 			LogicalConfirmReceivedLocation(flushPtr);
@@ -3536,7 +3536,7 @@ XLogSendLogical(void)
 	 * If first time through in this session, initialize flushPtr.  Otherwise,
 	 * we only need to update flushPtr if EndRecPtr is past it.
 	 */
-	if (flushPtr == InvalidXLogRecPtr ||
+	if (XLogRecPtrIsInvalid(flushPtr) ||
 		logical_decoding_ctx->reader->EndRecPtr >= flushPtr)
 	{
 		/*
-- 
2.34.1

v1-0018-make-use-of-XLogRecPtrIsInvalid-in-pg_receivewal..patchtext/x-diff; charset=us-asciiDownload
From 81f495d7c2739fe00e521b6bb191b8df4cf8ef4f Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Tue, 28 Oct 2025 06:41:06 +0000
Subject: [PATCH v1 18/20] make use of XLogRecPtrIsInvalid in pg_receivewal.c

---
 src/bin/pg_basebackup/pg_receivewal.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
 100.0% src/bin/pg_basebackup/

diff --git a/src/bin/pg_basebackup/pg_receivewal.c b/src/bin/pg_basebackup/pg_receivewal.c
index 289ca14dcfe..0cebdbca6c3 100644
--- a/src/bin/pg_basebackup/pg_receivewal.c
+++ b/src/bin/pg_basebackup/pg_receivewal.c
@@ -535,7 +535,7 @@ StreamLog(void)
 	 * Figure out where to start streaming.  First scan the local directory.
 	 */
 	stream.startpos = FindStreamingStart(&stream.timeline);
-	if (stream.startpos == InvalidXLogRecPtr)
+	if (XLogRecPtrIsInvalid(stream.startpos))
 	{
 		/*
 		 * Try to get the starting point from the slot if any.  This is
@@ -556,14 +556,14 @@ StreamLog(void)
 		 * If it the starting point is still not known, use the current WAL
 		 * flush value as last resort.
 		 */
-		if (stream.startpos == InvalidXLogRecPtr)
+		if (XLogRecPtrIsInvalid(stream.startpos))
 		{
 			stream.startpos = serverpos;
 			stream.timeline = servertli;
 		}
 	}
 
-	Assert(stream.startpos != InvalidXLogRecPtr &&
+	Assert(!XLogRecPtrIsInvalid(stream.startpos) &&
 		   stream.timeline != 0);
 
 	/*
-- 
2.34.1

v1-0019-make-use-of-XLogRecPtrIsInvalid-in-pg_recvlogical.patchtext/x-diff; charset=us-asciiDownload
From 4c143cd83eba7a7c7de41c2037faa6c1c0e448be Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Tue, 28 Oct 2025 06:43:24 +0000
Subject: [PATCH v1 19/20] make use of XLogRecPtrIsInvalid in pg_recvlogical.c

---
 src/bin/pg_basebackup/pg_recvlogical.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)
 100.0% src/bin/pg_basebackup/

diff --git a/src/bin/pg_basebackup/pg_recvlogical.c b/src/bin/pg_basebackup/pg_recvlogical.c
index 7a4d1a2d2ca..36184156f26 100644
--- a/src/bin/pg_basebackup/pg_recvlogical.c
+++ b/src/bin/pg_basebackup/pg_recvlogical.c
@@ -482,7 +482,7 @@ StreamLogicalLog(void)
 			}
 			replyRequested = copybuf[pos];
 
-			if (endpos != InvalidXLogRecPtr && walEnd >= endpos)
+			if (!XLogRecPtrIsInvalid(endpos) && walEnd >= endpos)
 			{
 				/*
 				 * If there's nothing to read on the socket until a keepalive
@@ -535,7 +535,7 @@ StreamLogicalLog(void)
 		/* Extract WAL location for this block */
 		cur_record_lsn = fe_recvint64(&copybuf[1]);
 
-		if (endpos != InvalidXLogRecPtr && cur_record_lsn > endpos)
+		if (!XLogRecPtrIsInvalid(endpos) && cur_record_lsn > endpos)
 		{
 			/*
 			 * We've read past our endpoint, so prepare to go away being
@@ -583,7 +583,7 @@ StreamLogicalLog(void)
 			goto error;
 		}
 
-		if (endpos != InvalidXLogRecPtr && cur_record_lsn == endpos)
+		if (!XLogRecPtrIsInvalid(endpos) && cur_record_lsn == endpos)
 		{
 			/* endpos was exactly the record we just processed, we're done */
 			if (!flushAndSendFeedback(conn, &now))
@@ -913,14 +913,14 @@ main(int argc, char **argv)
 		exit(1);
 	}
 
-	if (startpos != InvalidXLogRecPtr && (do_create_slot || do_drop_slot))
+	if (!XLogRecPtrIsInvalid(startpos) && (do_create_slot || do_drop_slot))
 	{
 		pg_log_error("cannot use --create-slot or --drop-slot together with --startpos");
 		pg_log_error_hint("Try \"%s --help\" for more information.", progname);
 		exit(1);
 	}
 
-	if (endpos != InvalidXLogRecPtr && !do_start_slot)
+	if (!XLogRecPtrIsInvalid(endpos) && !do_start_slot)
 	{
 		pg_log_error("--endpos may only be specified with --start");
 		pg_log_error_hint("Try \"%s --help\" for more information.", progname);
-- 
2.34.1

v1-0020-make-use-of-XLogRecPtrIsInvalid-in-pg_waldump.c.patchtext/x-diff; charset=us-asciiDownload
From 23ca9d19dbb0584756f0cd7be9aa123dac40217b Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Tue, 28 Oct 2025 06:45:47 +0000
Subject: [PATCH v1 20/20] make use of XLogRecPtrIsInvalid in pg_waldump.c

---
 src/bin/pg_waldump/pg_waldump.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
 100.0% src/bin/pg_waldump/

diff --git a/src/bin/pg_waldump/pg_waldump.c b/src/bin/pg_waldump/pg_waldump.c
index 13d3ec2f5be..620ab2d5e44 100644
--- a/src/bin/pg_waldump/pg_waldump.c
+++ b/src/bin/pg_waldump/pg_waldump.c
@@ -393,7 +393,7 @@ WALDumpReadPage(XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen,
 	int			count = XLOG_BLCKSZ;
 	WALReadError errinfo;
 
-	if (private->endptr != InvalidXLogRecPtr)
+	if (!XLogRecPtrIsInvalid(private->endptr))
 	{
 		if (targetPagePtr + XLOG_BLCKSZ <= private->endptr)
 			count = XLOG_BLCKSZ;
@@ -1213,7 +1213,7 @@ main(int argc, char **argv)
 	/* first find a valid recptr to start from */
 	first_record = XLogFindNextRecord(xlogreader_state, private.startptr);
 
-	if (first_record == InvalidXLogRecPtr)
+	if (XLogRecPtrIsInvalid(first_record))
 		pg_fatal("could not find a valid record after %X/%08X",
 				 LSN_FORMAT_ARGS(private.startptr));
 
-- 
2.34.1

#2Quan Zongliang
quanzongliang@yeah.net
In reply to: Bertrand Drouvot (#1)
Re: Consistently use the XLogRecPtrIsInvalid() macro

On 10/28/25 4:13 PM, Bertrand Drouvot wrote:

Hi hackers,

While working on refactoring some code in [1], one of the changes was:

-       if (initial_restart_lsn != InvalidXLogRecPtr &&
-           initial_restart_lsn < oldestLSN)
+       XLogRecPtr  restart_lsn = s->data.restart_lsn;
+
+       if (restart_lsn != InvalidXLogRecPtr &&
+           restart_lsn < oldestLSN)

Sawada-san suggested to use the XLogRecPtrIsInvalid() macro here.

But this != InvalidXLogRecPtr check was existing code, so why not consistently
use XLogRecPtrIsInvalid() where we check equality against InvalidXLogRecPtr?

At the time the current XLogRecPtrIsInvalid() has been introduced (0ab9d1c4b316)
all the InvalidXLogRecPtr equality checks were done using XLogRecPtrIsInvalid().

But since, it has changed: I looked at it and this is not the case anymore in
20 files.

PFA, patches to $SUBJECT. To ease the review, I created one patch per modified
file.

I suspect the same approach could be applied to some other macros too. Let's
start with XLogRecPtrIsInvalid() first.

Agree. This patch has made the code style more consistent. And using
such macros is also in line with the usual practice. Just like
OidIsValid and TransactionIdIsValid.

Show quoted text

I think that's one of the things we could do once a year, like Peter does with
his annual "clang-tidy" check ([2]).

Thoughts?

[1]: /messages/by-id/CAD21AoB_C6V1PLNs=SuOejgGh1o6ZHJMstD7X4X1b_z==LdH1Q@mail.gmail.com
[2]: /messages/by-id/CAH2-WzmxPQAF_ZhwrUo3rzVk3yYj_4mqbgiQXAGGO5nFYV3D8Q@mail.gmail.com

Regards,

#3Heikki Linnakangas
hlinnaka@iki.fi
In reply to: Quan Zongliang (#2)
Re: Consistently use the XLogRecPtrIsInvalid() macro

On 28/10/2025 10:53, Quan Zongliang wrote:

On 10/28/25 4:13 PM, Bertrand Drouvot wrote:

While working on refactoring some code in [1], one of the changes was:

-       if (initial_restart_lsn != InvalidXLogRecPtr &&
-           initial_restart_lsn < oldestLSN)
+       XLogRecPtr  restart_lsn = s->data.restart_lsn;
+
+       if (restart_lsn != InvalidXLogRecPtr &&
+           restart_lsn < oldestLSN)

Sawada-san suggested to use the XLogRecPtrIsInvalid() macro here.

But this != InvalidXLogRecPtr check was existing code, so why not
consistently use XLogRecPtrIsInvalid() where we check equality
against InvalidXLogRecPtr?

At the time the current XLogRecPtrIsInvalid() has been introduced
(0ab9d1c4b316) all the InvalidXLogRecPtr equality checks were done
using XLogRecPtrIsInvalid().

But since, it has changed: I looked at it and this is not the case
anymore in 20 files.

PFA, patches to $SUBJECT. To ease the review, I created one patch
per modified file.

I suspect the same approach could be applied to some other macros
too. Let's start with XLogRecPtrIsInvalid() first.

Agree. This patch has made the code style more consistent. And using
such macros is also in line with the usual practice. Just like
OidIsValid and TransactionIdIsValid.

Back in the day, XLogRecPtrIsInvalid() was needed because XLogRecPtr was
a struct. 'x == InvalidXLogRecPtr' simply did not work. I don't see much
need for it nowadays. In fact I wonder if we should go in the other
direction and replace XLogRecPtrIsInvalid(x) calls with 'x ==
InvalidXLogRecPtr'.

It's also a bit cumbersome that we have XLogRecPtrIsInvalid() rather
than XLogRecPtrIsValid(). That's inconsistent with OidIsValid and
TransactionIdInValid, and it leads to an awkward double negative 'if
(!XLogRecPtrIsInvalid(x))' if you want to check that 'x' is valid.

Overall I'm inclined to do nothing. But if anything, perhaps introduce
XLogRecPtrIsValid(x) and switch to that, or replace
XLogRecPtrIsInvalid(x) calls with 'x == InvalidXLogRecPtr'

- Heikki

#4Bertrand Drouvot
bertranddrouvot.pg@gmail.com
In reply to: Heikki Linnakangas (#3)
Re: Consistently use the XLogRecPtrIsInvalid() macro

Hi,

On Tue, Oct 28, 2025 at 01:40:24PM +0200, Heikki Linnakangas wrote:

On 28/10/2025 10:53, Quan Zongliang wrote:

On 10/28/25 4:13 PM, Bertrand Drouvot wrote:

While working on refactoring some code in [1], one of the changes was:

-������ if (initial_restart_lsn != InvalidXLogRecPtr &&
-���������� initial_restart_lsn < oldestLSN)
+������ XLogRecPtr� restart_lsn = s->data.restart_lsn;
+
+������ if (restart_lsn != InvalidXLogRecPtr &&
+���������� restart_lsn < oldestLSN)

Sawada-san suggested to use the XLogRecPtrIsInvalid() macro here.

But this != InvalidXLogRecPtr check was existing code, so why not
consistently use XLogRecPtrIsInvalid() where we check equality
against InvalidXLogRecPtr?

At the time the current XLogRecPtrIsInvalid() has been introduced
(0ab9d1c4b316) all the InvalidXLogRecPtr equality checks were done
using XLogRecPtrIsInvalid().

But since, it has changed: I looked at it and this is not the case
anymore in 20 files.

PFA, patches to $SUBJECT. To ease the review, I created one patch
per modified file.

I suspect the same approach could be applied to some other macros
too. Let's start with XLogRecPtrIsInvalid() first.

Agree. This patch has made the code style more consistent. And using
such macros is also in line with the usual practice. Just like
OidIsValid and TransactionIdIsValid.

Back in the day, XLogRecPtrIsInvalid() was needed because XLogRecPtr was a
struct. 'x == InvalidXLogRecPtr' simply did not work.

Thank you both for your feedback!

I don't see much need
for it nowadays. In fact I wonder if we should go in the other direction and
replace XLogRecPtrIsInvalid(x) calls with 'x == InvalidXLogRecPtr'.

That would be an option to ensure code consistency (related tp XLogRecPtr checks)
that will be hard to break (unless someone re-introduces a similar macro).

But OTOH that would introduce some kind of inconsistency with OidIsValid() and
TransactionIdIsValid() for example.

It's also a bit cumbersome that we have XLogRecPtrIsInvalid() rather than
XLogRecPtrIsValid(). That's inconsistent with OidIsValid and
TransactionIdInValid, and it leads to an awkward double negative 'if
(!XLogRecPtrIsInvalid(x))' if you want to check that 'x' is valid.

Agree.

Overall I'm inclined to do nothing. But if anything, perhaps introduce
XLogRecPtrIsValid(x) and switch to that, or replace XLogRecPtrIsInvalid(x)
calls with 'x == InvalidXLogRecPtr'

I do prefer to introduce XLogRecPtrIsValid(x) and switch to that. Then, do the
same kind of work on OidIsValid() and TransactionIdIsValid() and add an annual
check.

Idea is to get some code consistency while keeping macros which are valuable for
readability and centralize changes if any need to be done in the way we check
their validity.

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

#5Michael Paquier
michael@paquier.xyz
In reply to: Heikki Linnakangas (#3)
Re: Consistently use the XLogRecPtrIsInvalid() macro

On Tue, Oct 28, 2025 at 01:40:24PM +0200, Heikki Linnakangas wrote:

It's also a bit cumbersome that we have XLogRecPtrIsInvalid() rather than
XLogRecPtrIsValid(). That's inconsistent with OidIsValid and
TransactionIdInValid, and it leads to an awkward double negative 'if
(!XLogRecPtrIsInvalid(x))' if you want to check that 'x' is valid.

Overall I'm inclined to do nothing. But if anything, perhaps introduce
XLogRecPtrIsValid(x) and switch to that, or replace XLogRecPtrIsInvalid(x)
calls with 'x == InvalidXLogRecPtr'

The annoying part with eliminating XLogRecPtrIsInvalid() or replacing
it is that a bunch of external code would be broken, particularly
backup tools. I'd rather leave the beast alone.
--
Michael

#6Álvaro Herrera
alvherre@kurilemu.de
In reply to: Michael Paquier (#5)
Re: Consistently use the XLogRecPtrIsInvalid() macro

On 2025-Oct-28, Michael Paquier wrote:

The annoying part with eliminating XLogRecPtrIsInvalid() or replacing
it is that a bunch of external code would be broken, particularly
backup tools. I'd rather leave the beast alone.

Well, we don't have to remove it right away. We can simply not use it.
And maybe if the compiler supports it, make a static inline function in
the header with the [[deprecated]] attribute or
__attribute__((deprecated)) so that the tool developers get a warning
and migrate to using the new one. Then in a few years we remove it.

BTW we could use Coccinelle to replace all the XLogRecPtrIsInvalid()
calls with !XLogRecPtrIsValid(), as well as all places comparing an LSN
to InvalidXLogRecPtr or literal zero.

--
Álvaro Herrera PostgreSQL Developer — https://www.EnterpriseDB.com/

#7Bertrand Drouvot
bertranddrouvot.pg@gmail.com
In reply to: Álvaro Herrera (#6)
Re: Consistently use the XLogRecPtrIsInvalid() macro

Hi,

On Tue, Oct 28, 2025 at 04:05:34PM +0200, �lvaro Herrera wrote:

BTW we could use Coccinelle to replace all the XLogRecPtrIsInvalid()
calls with !XLogRecPtrIsValid(), as well as all places comparing an LSN
to InvalidXLogRecPtr or literal zero.

I did v1 the old way (shell script) and did not think about using
Coccinelle for this. That's a good idea and well suited for this purpose: I'll
work on it. Thanks for the suggestion!

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

#8Peter Eisentraut
peter@eisentraut.org
In reply to: Bertrand Drouvot (#4)
Re: Consistently use the XLogRecPtrIsInvalid() macro

On 28.10.25 13:33, Bertrand Drouvot wrote:

I do prefer to introduce XLogRecPtrIsValid(x) and switch to that. Then, do the
same kind of work on OidIsValid() and TransactionIdIsValid() and add an annual
check.

Idea is to get some code consistency while keeping macros which are valuable for
readability and centralize changes if any need to be done in the way we check
their validity.

If we wanted real type safety, we could turn XLogRecPtr back into a
struct, and then enforce the use of XLogRecPtrIsValid() and similar.
Otherwise, we should just acknowledge that it's an integer and use
integer code to deal with it. These *IsValid() and similar macros that
are there for "readability" but are not actually enforced other than by
some developers' willpower are just causing more work and inconsistency
in the long run.

#9Bertrand Drouvot
bertranddrouvot.pg@gmail.com
In reply to: Bertrand Drouvot (#7)
4 attachment(s)
Re: Consistently use the XLogRecPtrIsInvalid() macro

Hi,

On Tue, Oct 28, 2025 at 05:57:54PM +0000, Bertrand Drouvot wrote:

Hi,

On Tue, Oct 28, 2025 at 04:05:34PM +0200, �lvaro Herrera wrote:

BTW we could use Coccinelle to replace all the XLogRecPtrIsInvalid()
calls with !XLogRecPtrIsValid(), as well as all places comparing an LSN
to InvalidXLogRecPtr or literal zero.

I did v1 the old way (shell script) and did not think about using
Coccinelle for this. That's a good idea and well suited for this purpose: I'll
work on it. Thanks for the suggestion!

PFA a series of patches to implement what has been discussed above i.e:

- Introduce XLogRecPtrIsValid() and replace XLogRecPtrIsInvalid() calls: this
is done in 0001. The replacement changes have been generated by the Coccinelle
script [1]https://github.com/bdrouvot/coccinelle_on_pg/blob/main/replace_XLogRecPtrIsInvalid.cocci.

- 0002 deprecates XLogRecPtrIsInvalid(): it emits a warning message at compilation
time if XLogRecPtrIsInvalid() is in use in the code base.

- 0003 replaces InvalidXLogRecPtr comparisons with XLogRecPtrIsValid(). The
replacement changes have been generated by the Coccinelle script [2]https://github.com/bdrouvot/coccinelle_on_pg/blob/main/replace_InvalidXLogRecPtr_comparisons.cocci.

- 0004 replaces literal 0 comparisons on XLogRecPtr with XLogRecPtrIsValid(). The
replacement changes have been generated by the Coccinelle script [3]https://github.com/bdrouvot/coccinelle_on_pg/blob/main/replace_literal_0_comparisons.cocci.

[1]: https://github.com/bdrouvot/coccinelle_on_pg/blob/main/replace_XLogRecPtrIsInvalid.cocci
[2]: https://github.com/bdrouvot/coccinelle_on_pg/blob/main/replace_InvalidXLogRecPtr_comparisons.cocci
[3]: https://github.com/bdrouvot/coccinelle_on_pg/blob/main/replace_literal_0_comparisons.cocci

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

Attachments:

v2-0001-Introduce-XLogRecPtrIsValid-and-replace-XLogRecPt.patchtext/x-diff; charset=us-asciiDownload
From 4d525e4e199f913de7f852c1260eb68e98f9c1c7 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Wed, 29 Oct 2025 10:34:03 +0000
Subject: [PATCH v2 1/4] Introduce XLogRecPtrIsValid() and replace
 XLogRecPtrIsInvalid() calls

XLogRecPtrIsInvalid() is inconsistent with OidIsValid() and
TransactionIdIsValid(), and it leads to an awkward double negative 'if
(!XLogRecPtrIsInvalid(x))' to check that 'x' is valid.

This commit introduces XLogRecPtrIsValid() and replace all the
XLogRecPtrIsInvalid() calls.
---
 contrib/pg_walinspect/pg_walinspect.c         |  4 +--
 src/backend/access/gist/gist.c                |  4 +--
 src/backend/access/gist/gistget.c             |  4 +--
 src/backend/access/gist/gistutil.c            |  2 +-
 src/backend/access/heap/visibilitymap.c       |  4 +--
 src/backend/access/transam/clog.c             |  5 ++--
 src/backend/access/transam/slru.c             |  2 +-
 src/backend/access/transam/timeline.c         |  4 +--
 src/backend/access/transam/twophase.c         |  4 +--
 src/backend/access/transam/xlog.c             | 30 +++++++++----------
 src/backend/access/transam/xlogbackup.c       |  4 +--
 src/backend/access/transam/xlogreader.c       |  6 ++--
 src/backend/access/transam/xlogrecovery.c     | 12 ++++----
 src/backend/backup/backup_manifest.c          |  4 +--
 src/backend/backup/basebackup_incremental.c   |  2 +-
 src/backend/backup/walsummary.c               |  8 ++---
 src/backend/commands/subscriptioncmds.c       |  6 ++--
 src/backend/postmaster/walsummarizer.c        | 18 +++++------
 .../replication/logical/applyparallelworker.c |  4 +--
 src/backend/replication/logical/launcher.c    |  4 +--
 src/backend/replication/logical/logical.c     |  2 +-
 .../replication/logical/logicalfuncs.c        |  2 +-
 src/backend/replication/logical/slotsync.c    |  6 ++--
 src/backend/replication/logical/worker.c      | 16 +++++-----
 src/backend/replication/slot.c                | 10 +++----
 src/backend/replication/slotfuncs.c           | 16 +++++-----
 src/backend/replication/syncrep.c             | 10 +++----
 src/backend/replication/walreceiver.c         |  8 ++---
 src/backend/replication/walsender.c           | 22 +++++++-------
 src/backend/storage/buffer/bufmgr.c           |  2 +-
 src/bin/pg_basebackup/pg_receivewal.c         |  2 +-
 src/bin/pg_basebackup/pg_recvlogical.c        |  2 +-
 src/bin/pg_rewind/pg_rewind.c                 |  4 +--
 src/bin/pg_waldump/pg_waldump.c               | 10 +++----
 src/include/access/xlogdefs.h                 |  1 +
 35 files changed, 123 insertions(+), 121 deletions(-)
   4.3% src/backend/access/gist/
  27.4% src/backend/access/transam/
   6.6% src/backend/backup/
   7.7% src/backend/postmaster/
  14.3% src/backend/replication/logical/
  26.9% src/backend/replication/
   4.2% src/backend/
   3.8% src/bin/pg_waldump/

diff --git a/contrib/pg_walinspect/pg_walinspect.c b/contrib/pg_walinspect/pg_walinspect.c
index 501cea8fc1a..3c5e4a856a7 100644
--- a/contrib/pg_walinspect/pg_walinspect.c
+++ b/contrib/pg_walinspect/pg_walinspect.c
@@ -83,7 +83,7 @@ GetCurrentLSN(void)
 	else
 		curr_lsn = GetXLogReplayRecPtr(NULL);
 
-	Assert(!XLogRecPtrIsInvalid(curr_lsn));
+	Assert(XLogRecPtrIsValid(curr_lsn));
 
 	return curr_lsn;
 }
@@ -127,7 +127,7 @@ InitXLogReaderState(XLogRecPtr lsn)
 	/* first find a valid recptr to start from */
 	first_valid_record = XLogFindNextRecord(xlogreader, lsn);
 
-	if (XLogRecPtrIsInvalid(first_valid_record))
+	if (!XLogRecPtrIsValid(first_valid_record))
 		ereport(ERROR,
 				errmsg("could not find a valid record after %X/%08X",
 					   LSN_FORMAT_ARGS(lsn)));
diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c
index 5213cd71e97..3fb1a1285c5 100644
--- a/src/backend/access/gist/gist.c
+++ b/src/backend/access/gist/gist.c
@@ -682,7 +682,7 @@ gistdoinsert(Relation r, IndexTuple itup, Size freespace,
 			state.stack = stack = stack->parent;
 		}
 
-		if (XLogRecPtrIsInvalid(stack->lsn))
+		if (!XLogRecPtrIsValid(stack->lsn))
 			stack->buffer = ReadBuffer(state.r, stack->blkno);
 
 		/*
@@ -698,7 +698,7 @@ gistdoinsert(Relation r, IndexTuple itup, Size freespace,
 		stack->page = BufferGetPage(stack->buffer);
 		stack->lsn = xlocked ?
 			PageGetLSN(stack->page) : BufferGetLSNAtomic(stack->buffer);
-		Assert(!RelationNeedsWAL(state.r) || !XLogRecPtrIsInvalid(stack->lsn));
+		Assert(!RelationNeedsWAL(state.r) || XLogRecPtrIsValid(stack->lsn));
 
 		/*
 		 * If this page was split but the downlink was never inserted to the
diff --git a/src/backend/access/gist/gistget.c b/src/backend/access/gist/gistget.c
index 387d9972345..9ba45acfff3 100644
--- a/src/backend/access/gist/gistget.c
+++ b/src/backend/access/gist/gistget.c
@@ -46,7 +46,7 @@ gistkillitems(IndexScanDesc scan)
 	bool		killedsomething = false;
 
 	Assert(so->curBlkno != InvalidBlockNumber);
-	Assert(!XLogRecPtrIsInvalid(so->curPageLSN));
+	Assert(XLogRecPtrIsValid(so->curPageLSN));
 	Assert(so->killedItems != NULL);
 
 	buffer = ReadBuffer(scan->indexRelation, so->curBlkno);
@@ -353,7 +353,7 @@ gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem,
 	 * parentlsn < nsn), or if the system crashed after a page split but
 	 * before the downlink was inserted into the parent.
 	 */
-	if (!XLogRecPtrIsInvalid(pageItem->data.parentlsn) &&
+	if (XLogRecPtrIsValid(pageItem->data.parentlsn) &&
 		(GistFollowRight(page) ||
 		 pageItem->data.parentlsn < GistPageGetNSN(page)) &&
 		opaque->rightlink != InvalidBlockNumber /* sanity check */ )
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index 98b79608341..75272827837 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -1040,7 +1040,7 @@ gistGetFakeLSN(Relation rel)
 		Assert(!RelationNeedsWAL(rel));
 
 		/* No need for an actual record if we already have a distinct LSN */
-		if (!XLogRecPtrIsInvalid(lastlsn) && lastlsn == currlsn)
+		if (XLogRecPtrIsValid(lastlsn) && lastlsn == currlsn)
 			currlsn = gistXLogAssignLSN();
 
 		lastlsn = currlsn;
diff --git a/src/backend/access/heap/visibilitymap.c b/src/backend/access/heap/visibilitymap.c
index 2f5e61e2392..d14588e92ae 100644
--- a/src/backend/access/heap/visibilitymap.c
+++ b/src/backend/access/heap/visibilitymap.c
@@ -260,7 +260,7 @@ visibilitymap_set(Relation rel, BlockNumber heapBlk, Buffer heapBuf,
 		 flags, RelationGetRelationName(rel), heapBlk);
 #endif
 
-	Assert(InRecovery || XLogRecPtrIsInvalid(recptr));
+	Assert(InRecovery || !XLogRecPtrIsValid(recptr));
 	Assert(InRecovery || PageIsAllVisible(BufferGetPage(heapBuf)));
 	Assert((flags & VISIBILITYMAP_VALID_BITS) == flags);
 
@@ -292,7 +292,7 @@ visibilitymap_set(Relation rel, BlockNumber heapBlk, Buffer heapBuf,
 
 		if (RelationNeedsWAL(rel))
 		{
-			if (XLogRecPtrIsInvalid(recptr))
+			if (!XLogRecPtrIsValid(recptr))
 			{
 				Assert(!InRecovery);
 				recptr = log_heap_visible(rel, heapBuf, vmBuf, cutoff_xid, flags);
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index e80fbe109cf..ea43b432daf 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -381,7 +381,8 @@ TransactionIdSetPageStatusInternal(TransactionId xid, int nsubxids,
 	 * write-busy, since we don't care if the update reaches disk sooner than
 	 * we think.
 	 */
-	slotno = SimpleLruReadPage(XactCtl, pageno, XLogRecPtrIsInvalid(lsn), xid);
+	slotno = SimpleLruReadPage(XactCtl, pageno, !XLogRecPtrIsValid(lsn),
+							   xid);
 
 	/*
 	 * Set the main transaction id, if any.
@@ -705,7 +706,7 @@ TransactionIdSetStatusBit(TransactionId xid, XidStatus status, XLogRecPtr lsn, i
 	 * recovery. After recovery completes the next clog change will set the
 	 * LSN correctly.
 	 */
-	if (!XLogRecPtrIsInvalid(lsn))
+	if (XLogRecPtrIsValid(lsn))
 	{
 		int			lsnindex = GetLSNIndex(slotno, xid);
 
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index 5d3fcd62c94..77676d6d035 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -937,7 +937,7 @@ SlruPhysicalWritePage(SlruCtl ctl, int64 pageno, int slotno, SlruWriteAll fdata)
 				max_lsn = this_lsn;
 		}
 
-		if (!XLogRecPtrIsInvalid(max_lsn))
+		if (XLogRecPtrIsValid(max_lsn))
 		{
 			/*
 			 * As noted above, elog(ERROR) is not acceptable here, so if
diff --git a/src/backend/access/transam/timeline.c b/src/backend/access/transam/timeline.c
index 186eb91f609..ec3e323ec0c 100644
--- a/src/backend/access/transam/timeline.c
+++ b/src/backend/access/transam/timeline.c
@@ -549,8 +549,8 @@ tliOfPointInHistory(XLogRecPtr ptr, List *history)
 	{
 		TimeLineHistoryEntry *tle = (TimeLineHistoryEntry *) lfirst(cell);
 
-		if ((XLogRecPtrIsInvalid(tle->begin) || tle->begin <= ptr) &&
-			(XLogRecPtrIsInvalid(tle->end) || ptr < tle->end))
+		if ((!XLogRecPtrIsValid(tle->begin) || tle->begin <= ptr) &&
+			(!XLogRecPtrIsValid(tle->end) || ptr < tle->end))
 		{
 			/* found it */
 			return tle->tli;
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 33369fbe23a..8a92b292e56 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -2547,7 +2547,7 @@ PrepareRedoAdd(FullTransactionId fxid, char *buf,
 	 * the record is added to TwoPhaseState and it should have no
 	 * corresponding file in pg_twophase.
 	 */
-	if (!XLogRecPtrIsInvalid(start_lsn))
+	if (XLogRecPtrIsValid(start_lsn))
 	{
 		char		path[MAXPGPATH];
 
@@ -2587,7 +2587,7 @@ PrepareRedoAdd(FullTransactionId fxid, char *buf,
 	gxact->owner = hdr->owner;
 	gxact->locking_backend = INVALID_PROC_NUMBER;
 	gxact->valid = false;
-	gxact->ondisk = XLogRecPtrIsInvalid(start_lsn);
+	gxact->ondisk = !XLogRecPtrIsValid(start_lsn);
 	gxact->inredo = true;		/* yes, added in redo */
 	strcpy(gxact->gid, gid);
 
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index fd91bcd68ec..4b827c17cfa 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -1761,7 +1761,7 @@ WALReadFromBuffers(char *dstbuf, XLogRecPtr startptr, Size count,
 	if (RecoveryInProgress() || tli != GetWALInsertionTimeLine())
 		return 0;
 
-	Assert(!XLogRecPtrIsInvalid(startptr));
+	Assert(XLogRecPtrIsValid(startptr));
 
 	/*
 	 * Caller should ensure that the requested data has been inserted into WAL
@@ -2716,7 +2716,7 @@ UpdateMinRecoveryPoint(XLogRecPtr lsn, bool force)
 	 * available is replayed in this case.  This also saves from extra locks
 	 * taken on the control file from the startup process.
 	 */
-	if (XLogRecPtrIsInvalid(LocalMinRecoveryPoint) && InRecovery)
+	if (!XLogRecPtrIsValid(LocalMinRecoveryPoint) && InRecovery)
 	{
 		updateMinRecoveryPoint = false;
 		return;
@@ -2728,7 +2728,7 @@ UpdateMinRecoveryPoint(XLogRecPtr lsn, bool force)
 	LocalMinRecoveryPoint = ControlFile->minRecoveryPoint;
 	LocalMinRecoveryPointTLI = ControlFile->minRecoveryPointTLI;
 
-	if (XLogRecPtrIsInvalid(LocalMinRecoveryPoint))
+	if (!XLogRecPtrIsValid(LocalMinRecoveryPoint))
 		updateMinRecoveryPoint = false;
 	else if (force || LocalMinRecoveryPoint < lsn)
 	{
@@ -3148,7 +3148,7 @@ XLogNeedsFlush(XLogRecPtr record)
 		 * which cannot update its local copy of minRecoveryPoint as long as
 		 * it has not replayed all WAL available when doing crash recovery.
 		 */
-		if (XLogRecPtrIsInvalid(LocalMinRecoveryPoint) && InRecovery)
+		if (!XLogRecPtrIsValid(LocalMinRecoveryPoint) && InRecovery)
 		{
 			updateMinRecoveryPoint = false;
 			return false;
@@ -3169,7 +3169,7 @@ XLogNeedsFlush(XLogRecPtr record)
 		 * process doing crash recovery, which should not update the control
 		 * file value if crash recovery is still running.
 		 */
-		if (XLogRecPtrIsInvalid(LocalMinRecoveryPoint))
+		if (!XLogRecPtrIsValid(LocalMinRecoveryPoint))
 			updateMinRecoveryPoint = false;
 
 		/* check again */
@@ -5934,7 +5934,7 @@ StartupXLOG(void)
 	 */
 	if (InRecovery &&
 		(EndOfLog < LocalMinRecoveryPoint ||
-		 !XLogRecPtrIsInvalid(ControlFile->backupStartPoint)))
+		 XLogRecPtrIsValid(ControlFile->backupStartPoint)))
 	{
 		/*
 		 * Ran off end of WAL before reaching end-of-backup WAL record, or
@@ -5944,7 +5944,7 @@ StartupXLOG(void)
 		 */
 		if (ArchiveRecoveryRequested || ControlFile->backupEndRequired)
 		{
-			if (!XLogRecPtrIsInvalid(ControlFile->backupStartPoint) || ControlFile->backupEndRequired)
+			if (XLogRecPtrIsValid(ControlFile->backupStartPoint) || ControlFile->backupEndRequired)
 				ereport(FATAL,
 						(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 						 errmsg("WAL ends before end of online backup"),
@@ -6046,7 +6046,7 @@ StartupXLOG(void)
 	 * (It's critical to first write an OVERWRITE_CONTRECORD message, which
 	 * we'll do as soon as we're open for writing new WAL.)
 	 */
-	if (!XLogRecPtrIsInvalid(missingContrecPtr))
+	if (XLogRecPtrIsValid(missingContrecPtr))
 	{
 		/*
 		 * We should only have a missingContrecPtr if we're not switching to a
@@ -6056,7 +6056,7 @@ StartupXLOG(void)
 		 * disregard.
 		 */
 		Assert(newTLI == endOfRecoveryInfo->lastRecTLI);
-		Assert(!XLogRecPtrIsInvalid(abortedRecPtr));
+		Assert(XLogRecPtrIsValid(abortedRecPtr));
 		EndOfLog = missingContrecPtr;
 	}
 
@@ -6160,9 +6160,9 @@ StartupXLOG(void)
 	LocalSetXLogInsertAllowed();
 
 	/* If necessary, write overwrite-contrecord before doing anything else */
-	if (!XLogRecPtrIsInvalid(abortedRecPtr))
+	if (XLogRecPtrIsValid(abortedRecPtr))
 	{
-		Assert(!XLogRecPtrIsInvalid(missingContrecPtr));
+		Assert(XLogRecPtrIsValid(missingContrecPtr));
 		CreateOverwriteContrecordRecord(abortedRecPtr, missingContrecPtr, newTLI);
 	}
 
@@ -7686,7 +7686,7 @@ CreateRestartPoint(int flags)
 	 * restartpoint. It's assumed that flushing the buffers will do that as a
 	 * side-effect.
 	 */
-	if (XLogRecPtrIsInvalid(lastCheckPointRecPtr) ||
+	if (!XLogRecPtrIsValid(lastCheckPointRecPtr) ||
 		lastCheckPoint.redo <= ControlFile->checkPointCopy.redo)
 	{
 		ereport(DEBUG2,
@@ -7929,7 +7929,7 @@ GetWALAvailability(XLogRecPtr targetLSN)
 	/*
 	 * slot does not reserve WAL. Either deactivated, or has never been active
 	 */
-	if (XLogRecPtrIsInvalid(targetLSN))
+	if (!XLogRecPtrIsValid(targetLSN))
 		return WALAVAIL_INVALID_LSN;
 
 	/*
@@ -8345,8 +8345,8 @@ xlog_redo(XLogReaderState *record)
 		 * never arrive.
 		 */
 		if (ArchiveRecoveryRequested &&
-			!XLogRecPtrIsInvalid(ControlFile->backupStartPoint) &&
-			XLogRecPtrIsInvalid(ControlFile->backupEndPoint))
+			XLogRecPtrIsValid(ControlFile->backupStartPoint) &&
+			!XLogRecPtrIsValid(ControlFile->backupEndPoint))
 			ereport(PANIC,
 					(errmsg("online backup was canceled, recovery cannot continue")));
 
diff --git a/src/backend/access/transam/xlogbackup.c b/src/backend/access/transam/xlogbackup.c
index cda4b38b7d6..78908ea32b3 100644
--- a/src/backend/access/transam/xlogbackup.c
+++ b/src/backend/access/transam/xlogbackup.c
@@ -78,8 +78,8 @@ build_backup_content(BackupState *state, bool ishistoryfile)
 	}
 
 	/* either both istartpoint and istarttli should be set, or neither */
-	Assert(XLogRecPtrIsInvalid(state->istartpoint) == (state->istarttli == 0));
-	if (!XLogRecPtrIsInvalid(state->istartpoint))
+	Assert(!XLogRecPtrIsValid(state->istartpoint) == (state->istarttli == 0));
+	if (XLogRecPtrIsValid(state->istartpoint))
 	{
 		appendStringInfo(result, "INCREMENTAL FROM LSN: %X/%08X\n",
 						 LSN_FORMAT_ARGS(state->istartpoint));
diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index dcc8d4f9c1b..aad16127e60 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -231,7 +231,7 @@ WALOpenSegmentInit(WALOpenSegment *seg, WALSegmentContext *segcxt,
 void
 XLogBeginRead(XLogReaderState *state, XLogRecPtr RecPtr)
 {
-	Assert(!XLogRecPtrIsInvalid(RecPtr));
+	Assert(XLogRecPtrIsValid(RecPtr));
 
 	ResetDecoder(state);
 
@@ -343,7 +343,7 @@ XLogNextRecord(XLogReaderState *state, char **errormsg)
 		 * XLogBeginRead() or XLogNextRecord(), and is the location of the
 		 * error.
 		 */
-		Assert(!XLogRecPtrIsInvalid(state->EndRecPtr));
+		Assert(XLogRecPtrIsValid(state->EndRecPtr));
 
 		return NULL;
 	}
@@ -1398,7 +1398,7 @@ XLogFindNextRecord(XLogReaderState *state, XLogRecPtr RecPtr)
 	XLogPageHeader header;
 	char	   *errormsg;
 
-	Assert(!XLogRecPtrIsInvalid(RecPtr));
+	Assert(XLogRecPtrIsValid(RecPtr));
 
 	/* Make sure ReadPageInternal() can't return XLREAD_WOULDBLOCK. */
 	state->nonblocking = false;
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index 3e3c4da01a2..84df67b07d2 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -772,7 +772,7 @@ InitWalRecovery(ControlFileData *ControlFile, bool *wasShutdown_ptr,
 		 * emit a log message when we continue initializing from a base
 		 * backup.
 		 */
-		if (!XLogRecPtrIsInvalid(ControlFile->backupStartPoint))
+		if (XLogRecPtrIsValid(ControlFile->backupStartPoint))
 			ereport(LOG,
 					errmsg("restarting backup recovery with redo LSN %X/%08X",
 						   LSN_FORMAT_ARGS(ControlFile->backupStartPoint)));
@@ -867,7 +867,7 @@ InitWalRecovery(ControlFileData *ControlFile, bool *wasShutdown_ptr,
 	 * The min recovery point should be part of the requested timeline's
 	 * history, too.
 	 */
-	if (!XLogRecPtrIsInvalid(ControlFile->minRecoveryPoint) &&
+	if (XLogRecPtrIsValid(ControlFile->minRecoveryPoint) &&
 		tliOfPointInHistory(ControlFile->minRecoveryPoint - 1, expectedTLEs) !=
 		ControlFile->minRecoveryPointTLI)
 		ereport(FATAL,
@@ -2193,7 +2193,7 @@ CheckRecoveryConsistency(void)
 	 * During crash recovery, we don't reach a consistent state until we've
 	 * replayed all the WAL.
 	 */
-	if (XLogRecPtrIsInvalid(minRecoveryPoint))
+	if (!XLogRecPtrIsValid(minRecoveryPoint))
 		return;
 
 	Assert(InArchiveRecovery);
@@ -2208,7 +2208,7 @@ CheckRecoveryConsistency(void)
 	/*
 	 * Have we reached the point where our base backup was completed?
 	 */
-	if (!XLogRecPtrIsInvalid(backupEndPoint) &&
+	if (XLogRecPtrIsValid(backupEndPoint) &&
 		backupEndPoint <= lastReplayedEndRecPtr)
 	{
 		XLogRecPtr	saveBackupStartPoint = backupStartPoint;
@@ -2414,7 +2414,7 @@ checkTimeLineSwitch(XLogRecPtr lsn, TimeLineID newTLI, TimeLineID prevTLI,
 	 * branched before the timeline the min recovery point is on, and you
 	 * attempt to do PITR to the new timeline.
 	 */
-	if (!XLogRecPtrIsInvalid(minRecoveryPoint) &&
+	if (XLogRecPtrIsValid(minRecoveryPoint) &&
 		lsn < minRecoveryPoint &&
 		newTLI > minRecoveryPointTLI)
 		ereport(PANIC,
@@ -3177,7 +3177,7 @@ ReadRecord(XLogPrefetcher *xlogprefetcher, int emode,
 			 * overwrite contrecord in the wrong place, breaking everything.
 			 */
 			if (!ArchiveRecoveryRequested &&
-				!XLogRecPtrIsInvalid(xlogreader->abortedRecPtr))
+				XLogRecPtrIsValid(xlogreader->abortedRecPtr))
 			{
 				abortedRecPtr = xlogreader->abortedRecPtr;
 				missingContrecPtr = xlogreader->missingContrecPtr;
diff --git a/src/backend/backup/backup_manifest.c b/src/backend/backup/backup_manifest.c
index d05252f383c..dd76c9b0b63 100644
--- a/src/backend/backup/backup_manifest.c
+++ b/src/backend/backup/backup_manifest.c
@@ -242,7 +242,7 @@ AddWALInfoToBackupManifest(backup_manifest_info *manifest, XLogRecPtr startptr,
 		 * entry->end is InvalidXLogRecPtr, it means that the timeline has not
 		 * yet ended.)
 		 */
-		if (!XLogRecPtrIsInvalid(entry->end) && entry->end < startptr)
+		if (XLogRecPtrIsValid(entry->end) && entry->end < startptr)
 			continue;
 
 		/*
@@ -274,7 +274,7 @@ AddWALInfoToBackupManifest(backup_manifest_info *manifest, XLogRecPtr startptr,
 			 * better have arrived at the expected starting TLI. If not,
 			 * something's gone horribly wrong.
 			 */
-			if (XLogRecPtrIsInvalid(entry->begin))
+			if (!XLogRecPtrIsValid(entry->begin))
 				ereport(ERROR,
 						errmsg("expected start timeline %u but found timeline %u",
 							   starttli, entry->tli));
diff --git a/src/backend/backup/basebackup_incremental.c b/src/backend/backup/basebackup_incremental.c
index a0d48ff0fef..852ab577045 100644
--- a/src/backend/backup/basebackup_incremental.c
+++ b/src/backend/backup/basebackup_incremental.c
@@ -519,7 +519,7 @@ PrepareForIncrementalBackup(IncrementalBackupInfo *ib,
 		if (!WalSummariesAreComplete(tli_wslist, tli_start_lsn, tli_end_lsn,
 									 &tli_missing_lsn))
 		{
-			if (XLogRecPtrIsInvalid(tli_missing_lsn))
+			if (!XLogRecPtrIsValid(tli_missing_lsn))
 				ereport(ERROR,
 						(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 						 errmsg("WAL summaries are required on timeline %u from %X/%08X to %X/%08X, but no summaries for that timeline and LSN range exist",
diff --git a/src/backend/backup/walsummary.c b/src/backend/backup/walsummary.c
index c7a2c65cc6a..2689eae3328 100644
--- a/src/backend/backup/walsummary.c
+++ b/src/backend/backup/walsummary.c
@@ -67,9 +67,9 @@ GetWalSummaries(TimeLineID tli, XLogRecPtr start_lsn, XLogRecPtr end_lsn)
 		/* Skip if it doesn't match the filter criteria. */
 		if (tli != 0 && tli != file_tli)
 			continue;
-		if (!XLogRecPtrIsInvalid(start_lsn) && start_lsn >= file_end_lsn)
+		if (XLogRecPtrIsValid(start_lsn) && start_lsn >= file_end_lsn)
 			continue;
-		if (!XLogRecPtrIsInvalid(end_lsn) && end_lsn <= file_start_lsn)
+		if (XLogRecPtrIsValid(end_lsn) && end_lsn <= file_start_lsn)
 			continue;
 
 		/* Add it to the list. */
@@ -111,9 +111,9 @@ FilterWalSummaries(List *wslist, TimeLineID tli,
 		/* Skip if it doesn't match the filter criteria. */
 		if (tli != 0 && tli != ws->tli)
 			continue;
-		if (!XLogRecPtrIsInvalid(start_lsn) && start_lsn > ws->end_lsn)
+		if (XLogRecPtrIsValid(start_lsn) && start_lsn > ws->end_lsn)
 			continue;
-		if (!XLogRecPtrIsInvalid(end_lsn) && end_lsn < ws->start_lsn)
+		if (XLogRecPtrIsValid(end_lsn) && end_lsn < ws->start_lsn)
 			continue;
 
 		/* Add it to the result list. */
diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c
index 1f45444b499..ccf238f665b 100644
--- a/src/backend/commands/subscriptioncmds.c
+++ b/src/backend/commands/subscriptioncmds.c
@@ -393,7 +393,7 @@ parse_subscription_options(ParseState *pstate, List *stmt_options,
 				lsn = DatumGetLSN(DirectFunctionCall1(pg_lsn_in,
 													  CStringGetDatum(lsn_str)));
 
-				if (XLogRecPtrIsInvalid(lsn))
+				if (!XLogRecPtrIsValid(lsn))
 					ereport(ERROR,
 							(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 							 errmsg("invalid WAL location (LSN): %s", lsn_str)));
@@ -1893,7 +1893,7 @@ AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt,
 				 * If the user sets subskiplsn, we do a sanity check to make
 				 * sure that the specified LSN is a probable value.
 				 */
-				if (!XLogRecPtrIsInvalid(opts.lsn))
+				if (XLogRecPtrIsValid(opts.lsn))
 				{
 					RepOriginId originid;
 					char		originname[NAMEDATALEN];
@@ -1905,7 +1905,7 @@ AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt,
 					remote_lsn = replorigin_get_progress(originid, false);
 
 					/* Check the given LSN is at least a future LSN */
-					if (!XLogRecPtrIsInvalid(remote_lsn) && opts.lsn < remote_lsn)
+					if (XLogRecPtrIsValid(remote_lsn) && opts.lsn < remote_lsn)
 						ereport(ERROR,
 								(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 								 errmsg("skip WAL location (LSN %X/%08X) must be greater than origin LSN %X/%08X",
diff --git a/src/backend/postmaster/walsummarizer.c b/src/backend/postmaster/walsummarizer.c
index e1f142f20c7..c4a888a081c 100644
--- a/src/backend/postmaster/walsummarizer.c
+++ b/src/backend/postmaster/walsummarizer.c
@@ -342,7 +342,7 @@ WalSummarizerMain(const void *startup_data, size_t startup_data_len)
 	 * If we discover that WAL summarization is not enabled, just exit.
 	 */
 	current_lsn = GetOldestUnsummarizedLSN(&current_tli, &exact);
-	if (XLogRecPtrIsInvalid(current_lsn))
+	if (!XLogRecPtrIsValid(current_lsn))
 		proc_exit(0);
 
 	/*
@@ -379,7 +379,7 @@ WalSummarizerMain(const void *startup_data, size_t startup_data_len)
 		 * only have to do this once per timeline switch, we probably wouldn't
 		 * save any significant amount of work in practice.
 		 */
-		if (current_tli != latest_tli && XLogRecPtrIsInvalid(switch_lsn))
+		if (current_tli != latest_tli && !XLogRecPtrIsValid(switch_lsn))
 		{
 			List	   *tles = readTimeLineHistory(latest_tli);
 
@@ -394,7 +394,7 @@ WalSummarizerMain(const void *startup_data, size_t startup_data_len)
 		 * on this timeline. Switch to the next timeline and go around again,
 		 * backing up to the exact switch point if we passed it.
 		 */
-		if (!XLogRecPtrIsInvalid(switch_lsn) && current_lsn >= switch_lsn)
+		if (XLogRecPtrIsValid(switch_lsn) && current_lsn >= switch_lsn)
 		{
 			/* Restart summarization from switch point. */
 			current_tli = switch_tli;
@@ -419,7 +419,7 @@ WalSummarizerMain(const void *startup_data, size_t startup_data_len)
 		end_of_summary_lsn = SummarizeWAL(current_tli,
 										  current_lsn, exact,
 										  switch_lsn, latest_lsn);
-		Assert(!XLogRecPtrIsInvalid(end_of_summary_lsn));
+		Assert(XLogRecPtrIsValid(end_of_summary_lsn));
 		Assert(end_of_summary_lsn >= current_lsn);
 
 		/*
@@ -923,7 +923,7 @@ SummarizeWAL(TimeLineID tli, XLogRecPtr start_lsn, bool exact,
 	private_data = (SummarizerReadLocalXLogPrivate *)
 		palloc0(sizeof(SummarizerReadLocalXLogPrivate));
 	private_data->tli = tli;
-	private_data->historic = !XLogRecPtrIsInvalid(switch_lsn);
+	private_data->historic = XLogRecPtrIsValid(switch_lsn);
 	private_data->read_upto = maximum_lsn;
 
 	/* Create xlogreader. */
@@ -971,7 +971,7 @@ SummarizeWAL(TimeLineID tli, XLogRecPtr start_lsn, bool exact,
 	else
 	{
 		summary_start_lsn = XLogFindNextRecord(xlogreader, start_lsn);
-		if (XLogRecPtrIsInvalid(summary_start_lsn))
+		if (!XLogRecPtrIsValid(summary_start_lsn))
 		{
 			/*
 			 * If we hit end-of-WAL while trying to find the next valid
@@ -1058,7 +1058,7 @@ SummarizeWAL(TimeLineID tli, XLogRecPtr start_lsn, bool exact,
 		/* We shouldn't go backward. */
 		Assert(summary_start_lsn <= xlogreader->EndRecPtr);
 
-		if (!XLogRecPtrIsInvalid(switch_lsn) &&
+		if (XLogRecPtrIsValid(switch_lsn) &&
 			xlogreader->ReadRecPtr >= switch_lsn)
 		{
 			/*
@@ -1180,7 +1180,7 @@ SummarizeWAL(TimeLineID tli, XLogRecPtr start_lsn, bool exact,
 		 * If we have a switch LSN and have reached it, stop before reading
 		 * the next record.
 		 */
-		if (!XLogRecPtrIsInvalid(switch_lsn) &&
+		if (XLogRecPtrIsValid(switch_lsn) &&
 			xlogreader->EndRecPtr >= switch_lsn)
 			break;
 	}
@@ -1723,7 +1723,7 @@ MaybeRemoveOldWalSummaries(void)
 			 * If the WAL doesn't exist any more, we can remove it if the file
 			 * modification time is old enough.
 			 */
-			if (XLogRecPtrIsInvalid(oldest_lsn) || ws->end_lsn <= oldest_lsn)
+			if (!XLogRecPtrIsValid(oldest_lsn) || ws->end_lsn <= oldest_lsn)
 				RemoveWalSummaryIfOlderThan(ws, cutoff_time);
 
 			/*
diff --git a/src/backend/replication/logical/applyparallelworker.c b/src/backend/replication/logical/applyparallelworker.c
index 14325581afc..baa68c1ab6c 100644
--- a/src/backend/replication/logical/applyparallelworker.c
+++ b/src/backend/replication/logical/applyparallelworker.c
@@ -299,7 +299,7 @@ pa_can_start(void)
 	 * STREAM START message, and it doesn't seem worth sending the extra eight
 	 * bytes with the STREAM START to enable parallelism for this case.
 	 */
-	if (!XLogRecPtrIsInvalid(MySubscription->skiplsn))
+	if (XLogRecPtrIsValid(MySubscription->skiplsn))
 		return false;
 
 	/*
@@ -1640,7 +1640,7 @@ pa_xact_finish(ParallelApplyWorkerInfo *winfo, XLogRecPtr remote_lsn)
 	 */
 	pa_wait_for_xact_finish(winfo);
 
-	if (!XLogRecPtrIsInvalid(remote_lsn))
+	if (XLogRecPtrIsValid(remote_lsn))
 		store_flush_position(remote_lsn, winfo->shared->last_commit_end);
 
 	pa_free_worker(winfo);
diff --git a/src/backend/replication/logical/launcher.c b/src/backend/replication/logical/launcher.c
index 95b5cae9a55..d735114bc59 100644
--- a/src/backend/replication/logical/launcher.c
+++ b/src/backend/replication/logical/launcher.c
@@ -1621,7 +1621,7 @@ pg_stat_get_subscription(PG_FUNCTION_ARGS)
 		else
 			nulls[3] = true;
 
-		if (XLogRecPtrIsInvalid(worker.last_lsn))
+		if (!XLogRecPtrIsValid(worker.last_lsn))
 			nulls[4] = true;
 		else
 			values[4] = LSNGetDatum(worker.last_lsn);
@@ -1633,7 +1633,7 @@ pg_stat_get_subscription(PG_FUNCTION_ARGS)
 			nulls[6] = true;
 		else
 			values[6] = TimestampTzGetDatum(worker.last_recv_time);
-		if (XLogRecPtrIsInvalid(worker.reply_lsn))
+		if (!XLogRecPtrIsValid(worker.reply_lsn))
 			nulls[7] = true;
 		else
 			values[7] = LSNGetDatum(worker.reply_lsn);
diff --git a/src/backend/replication/logical/logical.c b/src/backend/replication/logical/logical.c
index 93ed2eb368e..79717b52941 100644
--- a/src/backend/replication/logical/logical.c
+++ b/src/backend/replication/logical/logical.c
@@ -388,7 +388,7 @@ CreateInitDecodingContext(const char *plugin,
 	slot->data.plugin = plugin_name;
 	SpinLockRelease(&slot->mutex);
 
-	if (XLogRecPtrIsInvalid(restart_lsn))
+	if (!XLogRecPtrIsValid(restart_lsn))
 		ReplicationSlotReserveWal();
 	else
 	{
diff --git a/src/backend/replication/logical/logicalfuncs.c b/src/backend/replication/logical/logicalfuncs.c
index 25f890ddeed..d78e486bca6 100644
--- a/src/backend/replication/logical/logicalfuncs.c
+++ b/src/backend/replication/logical/logicalfuncs.c
@@ -229,7 +229,7 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin
 		 * Wait for specified streaming replication standby servers (if any)
 		 * to confirm receipt of WAL up to wait_for_wal_lsn.
 		 */
-		if (XLogRecPtrIsInvalid(upto_lsn))
+		if (!XLogRecPtrIsValid(upto_lsn))
 			wait_for_wal_lsn = end_of_wal;
 		else
 			wait_for_wal_lsn = Min(upto_lsn, end_of_wal);
diff --git a/src/backend/replication/logical/slotsync.c b/src/backend/replication/logical/slotsync.c
index b122d99b009..8b4afd87dc9 100644
--- a/src/backend/replication/logical/slotsync.c
+++ b/src/backend/replication/logical/slotsync.c
@@ -493,7 +493,7 @@ reserve_wal_for_local_slot(XLogRecPtr restart_lsn)
 	ReplicationSlot *slot = MyReplicationSlot;
 
 	Assert(slot != NULL);
-	Assert(XLogRecPtrIsInvalid(slot->data.restart_lsn));
+	Assert(!XLogRecPtrIsValid(slot->data.restart_lsn));
 
 	while (true)
 	{
@@ -899,8 +899,8 @@ synchronize_slots(WalReceiverConn *wrconn)
 		 * pg_replication_slots view, then we can avoid fetching RS_EPHEMERAL
 		 * slots in the first place.
 		 */
-		if ((XLogRecPtrIsInvalid(remote_slot->restart_lsn) ||
-			 XLogRecPtrIsInvalid(remote_slot->confirmed_lsn) ||
+		if ((!XLogRecPtrIsValid(remote_slot->restart_lsn) ||
+			 !XLogRecPtrIsValid(remote_slot->confirmed_lsn) ||
 			 !TransactionIdIsValid(remote_slot->catalog_xmin)) &&
 			remote_slot->invalidated == RS_INVAL_NONE)
 			pfree(remote_slot);
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index 7edd1c9cf06..e6da007b460 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -514,7 +514,7 @@ bool		InitializingApplyWorker = false;
  * by the user.
  */
 static XLogRecPtr skip_xact_finish_lsn = InvalidXLogRecPtr;
-#define is_skipping_changes() (unlikely(!XLogRecPtrIsInvalid(skip_xact_finish_lsn)))
+#define is_skipping_changes() (unlikely(XLogRecPtrIsValid(skip_xact_finish_lsn)))
 
 /* BufFile handle of the current streaming file */
 static BufFile *stream_fd = NULL;
@@ -4103,7 +4103,7 @@ LogicalRepApplyLoop(XLogRecPtr last_received)
 						 * due to a bug, we don't want to proceed as it can
 						 * incorrectly advance oldest_nonremovable_xid.
 						 */
-						if (XLogRecPtrIsInvalid(rdt_data.remote_lsn))
+						if (!XLogRecPtrIsValid(rdt_data.remote_lsn))
 							elog(ERROR, "cannot get the latest WAL position from the publisher");
 
 						maybe_advance_nonremovable_xid(&rdt_data, true);
@@ -4587,7 +4587,7 @@ wait_for_publisher_status(RetainDeadTuplesData *rdt_data,
 static void
 wait_for_local_flush(RetainDeadTuplesData *rdt_data)
 {
-	Assert(!XLogRecPtrIsInvalid(rdt_data->remote_lsn) &&
+	Assert(XLogRecPtrIsValid(rdt_data->remote_lsn) &&
 		   TransactionIdIsValid(rdt_data->candidate_xid));
 
 	/*
@@ -5993,7 +5993,7 @@ maybe_start_skipping_changes(XLogRecPtr finish_lsn)
 	 * function is called for every remote transaction and we assume that
 	 * skipping the transaction is not used often.
 	 */
-	if (likely(XLogRecPtrIsInvalid(MySubscription->skiplsn) ||
+	if (likely(!XLogRecPtrIsValid(MySubscription->skiplsn) ||
 			   MySubscription->skiplsn != finish_lsn))
 		return;
 
@@ -6039,7 +6039,7 @@ clear_subscription_skip_lsn(XLogRecPtr finish_lsn)
 	XLogRecPtr	myskiplsn = MySubscription->skiplsn;
 	bool		started_tx = false;
 
-	if (likely(XLogRecPtrIsInvalid(myskiplsn)) || am_parallel_apply_worker())
+	if (likely(!XLogRecPtrIsValid(myskiplsn)) || am_parallel_apply_worker())
 		return;
 
 	if (!IsTransactionState())
@@ -6135,7 +6135,7 @@ apply_error_callback(void *arg)
 			errcontext("processing remote data for replication origin \"%s\" during message type \"%s\"",
 					   errarg->origin_name,
 					   logicalrep_message_type(errarg->command));
-		else if (XLogRecPtrIsInvalid(errarg->finish_lsn))
+		else if (!XLogRecPtrIsValid(errarg->finish_lsn))
 			errcontext("processing remote data for replication origin \"%s\" during message type \"%s\" in transaction %u",
 					   errarg->origin_name,
 					   logicalrep_message_type(errarg->command),
@@ -6151,7 +6151,7 @@ apply_error_callback(void *arg)
 	{
 		if (errarg->remote_attnum < 0)
 		{
-			if (XLogRecPtrIsInvalid(errarg->finish_lsn))
+			if (!XLogRecPtrIsValid(errarg->finish_lsn))
 				errcontext("processing remote data for replication origin \"%s\" during message type \"%s\" for replication target relation \"%s.%s\" in transaction %u",
 						   errarg->origin_name,
 						   logicalrep_message_type(errarg->command),
@@ -6169,7 +6169,7 @@ apply_error_callback(void *arg)
 		}
 		else
 		{
-			if (XLogRecPtrIsInvalid(errarg->finish_lsn))
+			if (!XLogRecPtrIsValid(errarg->finish_lsn))
 				errcontext("processing remote data for replication origin \"%s\" during message type \"%s\" for replication target relation \"%s.%s\" column \"%s\" in transaction %u",
 						   errarg->origin_name,
 						   logicalrep_message_type(errarg->command),
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index 6363030808f..0cb93dc90f2 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -1730,7 +1730,7 @@ static inline bool
 CanInvalidateIdleSlot(ReplicationSlot *s)
 {
 	return (idle_replication_slot_timeout_secs != 0 &&
-			!XLogRecPtrIsInvalid(s->data.restart_lsn) &&
+			XLogRecPtrIsValid(s->data.restart_lsn) &&
 			s->inactive_since > 0 &&
 			!(RecoveryInProgress() && s->data.synced));
 }
@@ -2922,7 +2922,7 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
 	 * Don't need to wait for the standbys to catch up if they are already
 	 * beyond the specified WAL location.
 	 */
-	if (!XLogRecPtrIsInvalid(ss_oldest_flush_lsn) &&
+	if (XLogRecPtrIsValid(ss_oldest_flush_lsn) &&
 		ss_oldest_flush_lsn >= wait_for_lsn)
 		return true;
 
@@ -2993,7 +2993,7 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
 			break;
 		}
 
-		if (XLogRecPtrIsInvalid(restart_lsn) || restart_lsn < wait_for_lsn)
+		if (!XLogRecPtrIsValid(restart_lsn) || restart_lsn < wait_for_lsn)
 		{
 			/* Log a message if no active_pid for this physical slot */
 			if (inactive)
@@ -3012,7 +3012,7 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
 
 		Assert(restart_lsn >= wait_for_lsn);
 
-		if (XLogRecPtrIsInvalid(min_restart_lsn) ||
+		if (!XLogRecPtrIsValid(min_restart_lsn) ||
 			min_restart_lsn > restart_lsn)
 			min_restart_lsn = restart_lsn;
 
@@ -3031,7 +3031,7 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
 		return false;
 
 	/* The ss_oldest_flush_lsn must not retreat. */
-	Assert(XLogRecPtrIsInvalid(ss_oldest_flush_lsn) ||
+	Assert(!XLogRecPtrIsValid(ss_oldest_flush_lsn) ||
 		   min_restart_lsn >= ss_oldest_flush_lsn);
 
 	ss_oldest_flush_lsn = min_restart_lsn;
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index b8f21153e7b..5aecd5c6a50 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -46,7 +46,7 @@ create_physical_replication_slot(char *name, bool immediately_reserve,
 	if (immediately_reserve)
 	{
 		/* Reserve WAL as the user asked for it */
-		if (XLogRecPtrIsInvalid(restart_lsn))
+		if (!XLogRecPtrIsValid(restart_lsn))
 			ReplicationSlotReserveWal();
 		else
 			MyReplicationSlot->data.restart_lsn = restart_lsn;
@@ -357,7 +357,7 @@ pg_get_replication_slots(PG_FUNCTION_ARGS)
 				 *
 				 * If we do change it, save the state for safe_wal_size below.
 				 */
-				if (!XLogRecPtrIsInvalid(slot_contents.data.restart_lsn))
+				if (XLogRecPtrIsValid(slot_contents.data.restart_lsn))
 				{
 					int			pid;
 
@@ -407,7 +407,7 @@ pg_get_replication_slots(PG_FUNCTION_ARGS)
 		values[i++] = BoolGetDatum(slot_contents.data.two_phase);
 
 		if (slot_contents.data.two_phase &&
-			!XLogRecPtrIsInvalid(slot_contents.data.two_phase_at))
+			XLogRecPtrIsValid(slot_contents.data.two_phase_at))
 			values[i++] = LSNGetDatum(slot_contents.data.two_phase_at);
 		else
 			nulls[i++] = true;
@@ -523,7 +523,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 
 	CheckSlotPermissions();
 
-	if (XLogRecPtrIsInvalid(moveto))
+	if (!XLogRecPtrIsValid(moveto))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("invalid target WAL LSN")));
@@ -545,7 +545,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	ReplicationSlotAcquire(NameStr(*slotname), true, true);
 
 	/* A slot whose restart_lsn has never been reserved cannot be advanced */
-	if (XLogRecPtrIsInvalid(MyReplicationSlot->data.restart_lsn))
+	if (!XLogRecPtrIsValid(MyReplicationSlot->data.restart_lsn))
 		ereport(ERROR,
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 				 errmsg("replication slot \"%s\" cannot be advanced",
@@ -679,7 +679,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 						NameStr(*src_name))));
 
 	/* Copying non-reserved slot doesn't make sense */
-	if (XLogRecPtrIsInvalid(src_restart_lsn))
+	if (!XLogRecPtrIsValid(src_restart_lsn))
 		ereport(ERROR,
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 				 errmsg("cannot copy a replication slot that doesn't reserve WAL")));
@@ -785,7 +785,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 					 errdetail("The source replication slot was modified incompatibly during the copy operation.")));
 
 		/* The source slot must have a consistent snapshot */
-		if (src_islogical && XLogRecPtrIsInvalid(copy_confirmed_flush))
+		if (src_islogical && !XLogRecPtrIsValid(copy_confirmed_flush))
 			ereport(ERROR,
 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 					 errmsg("cannot copy unfinished logical replication slot \"%s\"",
@@ -840,7 +840,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 	/* All done.  Set up the return values */
 	values[0] = NameGetDatum(dst_name);
 	nulls[0] = false;
-	if (!XLogRecPtrIsInvalid(MyReplicationSlot->data.confirmed_flush))
+	if (XLogRecPtrIsValid(MyReplicationSlot->data.confirmed_flush))
 	{
 		values[1] = LSNGetDatum(MyReplicationSlot->data.confirmed_flush);
 		nulls[1] = false;
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index 32cf3a48b89..a0c79958fd5 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -493,7 +493,7 @@ SyncRepReleaseWaiters(void)
 	if (MyWalSnd->sync_standby_priority == 0 ||
 		(MyWalSnd->state != WALSNDSTATE_STREAMING &&
 		 MyWalSnd->state != WALSNDSTATE_STOPPING) ||
-		XLogRecPtrIsInvalid(MyWalSnd->flush))
+		!XLogRecPtrIsValid(MyWalSnd->flush))
 	{
 		announce_next_takeover = true;
 		return;
@@ -676,11 +676,11 @@ SyncRepGetOldestSyncRecPtr(XLogRecPtr *writePtr,
 		XLogRecPtr	flush = sync_standbys[i].flush;
 		XLogRecPtr	apply = sync_standbys[i].apply;
 
-		if (XLogRecPtrIsInvalid(*writePtr) || *writePtr > write)
+		if (!XLogRecPtrIsValid(*writePtr) || *writePtr > write)
 			*writePtr = write;
-		if (XLogRecPtrIsInvalid(*flushPtr) || *flushPtr > flush)
+		if (!XLogRecPtrIsValid(*flushPtr) || *flushPtr > flush)
 			*flushPtr = flush;
-		if (XLogRecPtrIsInvalid(*applyPtr) || *applyPtr > apply)
+		if (!XLogRecPtrIsValid(*applyPtr) || *applyPtr > apply)
 			*applyPtr = apply;
 	}
 }
@@ -799,7 +799,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 			continue;
 
 		/* Must have a valid flush position */
-		if (XLogRecPtrIsInvalid(stby->flush))
+		if (!XLogRecPtrIsValid(stby->flush))
 			continue;
 
 		/* OK, it's a candidate */
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index 7361ffc9dcf..2ee8fecee26 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1469,16 +1469,16 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	{
 		values[1] = CStringGetTextDatum(WalRcvGetStateString(state));
 
-		if (XLogRecPtrIsInvalid(receive_start_lsn))
+		if (!XLogRecPtrIsValid(receive_start_lsn))
 			nulls[2] = true;
 		else
 			values[2] = LSNGetDatum(receive_start_lsn);
 		values[3] = Int32GetDatum(receive_start_tli);
-		if (XLogRecPtrIsInvalid(written_lsn))
+		if (!XLogRecPtrIsValid(written_lsn))
 			nulls[4] = true;
 		else
 			values[4] = LSNGetDatum(written_lsn);
-		if (XLogRecPtrIsInvalid(flushed_lsn))
+		if (!XLogRecPtrIsValid(flushed_lsn))
 			nulls[5] = true;
 		else
 			values[5] = LSNGetDatum(flushed_lsn);
@@ -1491,7 +1491,7 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 			nulls[8] = true;
 		else
 			values[8] = TimestampTzGetDatum(last_receipt_time);
-		if (XLogRecPtrIsInvalid(latest_end_lsn))
+		if (!XLogRecPtrIsValid(latest_end_lsn))
 			nulls[9] = true;
 		else
 			values[9] = LSNGetDatum(latest_end_lsn);
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 548eafa7a73..b6dfb230d0d 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -529,7 +529,7 @@ ReadReplicationSlot(ReadReplicationSlotCmd *cmd)
 		i++;
 
 		/* start LSN */
-		if (!XLogRecPtrIsInvalid(slot_contents.data.restart_lsn))
+		if (XLogRecPtrIsValid(slot_contents.data.restart_lsn))
 		{
 			char		xloc[64];
 
@@ -541,7 +541,7 @@ ReadReplicationSlot(ReadReplicationSlotCmd *cmd)
 		i++;
 
 		/* timeline this WAL was produced on */
-		if (!XLogRecPtrIsInvalid(slot_contents.data.restart_lsn))
+		if (XLogRecPtrIsValid(slot_contents.data.restart_lsn))
 		{
 			TimeLineID	slots_position_timeline;
 			TimeLineID	current_timeline;
@@ -906,7 +906,7 @@ StartReplication(StartReplicationCmd *cmd)
 			 * that's older than the switchpoint, if it's still in the same
 			 * WAL segment.
 			 */
-			if (!XLogRecPtrIsInvalid(switchpoint) &&
+			if (XLogRecPtrIsValid(switchpoint) &&
 				switchpoint < cmd->startpoint)
 			{
 				ereport(ERROR,
@@ -1827,7 +1827,7 @@ WalSndWaitForWal(XLogRecPtr loc)
 	 * receipt of WAL up to RecentFlushPtr. This is particularly interesting
 	 * if we're far behind.
 	 */
-	if (!XLogRecPtrIsInvalid(RecentFlushPtr) &&
+	if (XLogRecPtrIsValid(RecentFlushPtr) &&
 		!NeedToWaitForWal(loc, RecentFlushPtr, &wait_event))
 		return RecentFlushPtr;
 
@@ -3597,7 +3597,7 @@ WalSndDone(WalSndSendDataCallback send_data)
 	 * flush location if valid, write otherwise. Tools like pg_receivewal will
 	 * usually (unless in synchronous mode) return an invalid flush location.
 	 */
-	replicatedPtr = XLogRecPtrIsInvalid(MyWalSnd->flush) ?
+	replicatedPtr = !XLogRecPtrIsValid(MyWalSnd->flush) ?
 		MyWalSnd->write : MyWalSnd->flush;
 
 	if (WalSndCaughtUp && sentPtr == replicatedPtr &&
@@ -4073,19 +4073,19 @@ pg_stat_get_wal_senders(PG_FUNCTION_ARGS)
 		{
 			values[1] = CStringGetTextDatum(WalSndGetStateString(state));
 
-			if (XLogRecPtrIsInvalid(sent_ptr))
+			if (!XLogRecPtrIsValid(sent_ptr))
 				nulls[2] = true;
 			values[2] = LSNGetDatum(sent_ptr);
 
-			if (XLogRecPtrIsInvalid(write))
+			if (!XLogRecPtrIsValid(write))
 				nulls[3] = true;
 			values[3] = LSNGetDatum(write);
 
-			if (XLogRecPtrIsInvalid(flush))
+			if (!XLogRecPtrIsValid(flush))
 				nulls[4] = true;
 			values[4] = LSNGetDatum(flush);
 
-			if (XLogRecPtrIsInvalid(apply))
+			if (!XLogRecPtrIsValid(apply))
 				nulls[5] = true;
 			values[5] = LSNGetDatum(apply);
 
@@ -4094,7 +4094,7 @@ pg_stat_get_wal_senders(PG_FUNCTION_ARGS)
 			 * which always returns an invalid flush location, as an
 			 * asynchronous standby.
 			 */
-			priority = XLogRecPtrIsInvalid(flush) ? 0 : priority;
+			priority = !XLogRecPtrIsValid(flush) ? 0 : priority;
 
 			if (writeLag < 0)
 				nulls[6] = true;
@@ -4165,7 +4165,7 @@ WalSndKeepalive(bool requestReply, XLogRecPtr writePtr)
 	/* construct the message... */
 	resetStringInfo(&output_message);
 	pq_sendbyte(&output_message, PqReplMsg_Keepalive);
-	pq_sendint64(&output_message, XLogRecPtrIsInvalid(writePtr) ? sentPtr : writePtr);
+	pq_sendint64(&output_message, !XLogRecPtrIsValid(writePtr) ? sentPtr : writePtr);
 	pq_sendint64(&output_message, GetCurrentTimestamp());
 	pq_sendbyte(&output_message, requestReply ? 1 : 0);
 
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index e8544acb784..1b5ef9ce10a 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -5545,7 +5545,7 @@ MarkBufferDirtyHint(Buffer buffer, bool buffer_std)
 			 * checksum here. That will happen when the page is written
 			 * sometime later in this checkpoint cycle.
 			 */
-			if (!XLogRecPtrIsInvalid(lsn))
+			if (XLogRecPtrIsValid(lsn))
 				PageSetLSN(page, lsn);
 		}
 
diff --git a/src/bin/pg_basebackup/pg_receivewal.c b/src/bin/pg_basebackup/pg_receivewal.c
index 289ca14dcfe..3e6f4a7fc48 100644
--- a/src/bin/pg_basebackup/pg_receivewal.c
+++ b/src/bin/pg_basebackup/pg_receivewal.c
@@ -192,7 +192,7 @@ stop_streaming(XLogRecPtr xlogpos, uint32 timeline, bool segment_finished)
 					LSN_FORMAT_ARGS(xlogpos),
 					timeline);
 
-	if (!XLogRecPtrIsInvalid(endpos) && endpos < xlogpos)
+	if (XLogRecPtrIsValid(endpos) && endpos < xlogpos)
 	{
 		if (verbose)
 			pg_log_info("stopped log streaming at %X/%08X (timeline %u)",
diff --git a/src/bin/pg_basebackup/pg_recvlogical.c b/src/bin/pg_basebackup/pg_recvlogical.c
index 7a4d1a2d2ca..6739784a993 100644
--- a/src/bin/pg_basebackup/pg_recvlogical.c
+++ b/src/bin/pg_basebackup/pg_recvlogical.c
@@ -1080,7 +1080,7 @@ prepareToTerminate(PGconn *conn, XLogRecPtr endpos, StreamStopReason reason,
 							LSN_FORMAT_ARGS(endpos));
 				break;
 			case STREAM_STOP_END_OF_WAL:
-				Assert(!XLogRecPtrIsInvalid(lsn));
+				Assert(XLogRecPtrIsValid(lsn));
 				pg_log_info("end position %X/%08X reached by WAL record at %X/%08X",
 							LSN_FORMAT_ARGS(endpos), LSN_FORMAT_ARGS(lsn));
 				break;
diff --git a/src/bin/pg_rewind/pg_rewind.c b/src/bin/pg_rewind/pg_rewind.c
index 1b953692b17..27c514f934a 100644
--- a/src/bin/pg_rewind/pg_rewind.c
+++ b/src/bin/pg_rewind/pg_rewind.c
@@ -850,9 +850,9 @@ progress_report(bool finished)
 static XLogRecPtr
 MinXLogRecPtr(XLogRecPtr a, XLogRecPtr b)
 {
-	if (XLogRecPtrIsInvalid(a))
+	if (!XLogRecPtrIsValid(a))
 		return b;
-	else if (XLogRecPtrIsInvalid(b))
+	else if (!XLogRecPtrIsValid(b))
 		return a;
 	else
 		return Min(a, b);
diff --git a/src/bin/pg_waldump/pg_waldump.c b/src/bin/pg_waldump/pg_waldump.c
index 13d3ec2f5be..19cf5461eac 100644
--- a/src/bin/pg_waldump/pg_waldump.c
+++ b/src/bin/pg_waldump/pg_waldump.c
@@ -637,7 +637,7 @@ XLogDumpDisplayStats(XLogDumpConfig *config, XLogStats *stats)
 	/*
 	 * Leave if no stats have been computed yet, as tracked by the end LSN.
 	 */
-	if (XLogRecPtrIsInvalid(stats->endptr))
+	if (!XLogRecPtrIsValid(stats->endptr))
 		return;
 
 	/*
@@ -1136,7 +1136,7 @@ main(int argc, char **argv)
 		/* parse position from file */
 		XLogFromFileName(fname, &private.timeline, &segno, WalSegSz);
 
-		if (XLogRecPtrIsInvalid(private.startptr))
+		if (!XLogRecPtrIsValid(private.startptr))
 			XLogSegNoOffsetToRecPtr(segno, 0, WalSegSz, private.startptr);
 		else if (!XLByteInSeg(private.startptr, segno, WalSegSz))
 		{
@@ -1147,7 +1147,7 @@ main(int argc, char **argv)
 		}
 
 		/* no second file specified, set end position */
-		if (!(optind + 1 < argc) && XLogRecPtrIsInvalid(private.endptr))
+		if (!(optind + 1 < argc) && !XLogRecPtrIsValid(private.endptr))
 			XLogSegNoOffsetToRecPtr(segno + 1, 0, WalSegSz, private.endptr);
 
 		/* parse ENDSEG if passed */
@@ -1170,7 +1170,7 @@ main(int argc, char **argv)
 				pg_fatal("ENDSEG %s is before STARTSEG %s",
 						 argv[optind + 1], argv[optind]);
 
-			if (XLogRecPtrIsInvalid(private.endptr))
+			if (!XLogRecPtrIsValid(private.endptr))
 				XLogSegNoOffsetToRecPtr(endsegno + 1, 0, WalSegSz,
 										private.endptr);
 
@@ -1192,7 +1192,7 @@ main(int argc, char **argv)
 		waldir = identify_target_directory(waldir, NULL);
 
 	/* we don't know what to print */
-	if (XLogRecPtrIsInvalid(private.startptr))
+	if (!XLogRecPtrIsValid(private.startptr))
 	{
 		pg_log_error("no start WAL location given");
 		goto bad_argument;
diff --git a/src/include/access/xlogdefs.h b/src/include/access/xlogdefs.h
index 2397fb24115..33b9913e71e 100644
--- a/src/include/access/xlogdefs.h
+++ b/src/include/access/xlogdefs.h
@@ -27,6 +27,7 @@ typedef uint64 XLogRecPtr;
  */
 #define InvalidXLogRecPtr	0
 #define XLogRecPtrIsInvalid(r)	((r) == InvalidXLogRecPtr)
+#define XLogRecPtrIsValid(r) ((r) != InvalidXLogRecPtr)
 
 /*
  * First LSN to use for "fake" LSNs.
-- 
2.34.1

v2-0002-Deprecate-XLogRecPtrIsInvalid.patchtext/x-diff; charset=us-asciiDownload
From 5d8aa347afddd8fb2ff09390134c882efc97b718 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Wed, 29 Oct 2025 10:57:17 +0000
Subject: [PATCH v2 2/4] Deprecate XLogRecPtrIsInvalid()

Emit a warning message at compilation time if XLogRecPtrIsInvalid() is in use in
the code base.
---
 src/include/access/xlogdefs.h | 20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)
 100.0% src/include/access/

diff --git a/src/include/access/xlogdefs.h b/src/include/access/xlogdefs.h
index 33b9913e71e..6eebf86342e 100644
--- a/src/include/access/xlogdefs.h
+++ b/src/include/access/xlogdefs.h
@@ -26,9 +26,27 @@ typedef uint64 XLogRecPtr;
  * record can begin at zero.
  */
 #define InvalidXLogRecPtr	0
-#define XLogRecPtrIsInvalid(r)	((r) == InvalidXLogRecPtr)
 #define XLogRecPtrIsValid(r) ((r) != InvalidXLogRecPtr)
 
+/*
+ * XLogRecPtrIsInvalid
+ *
+ * Deprecated: Use XLogRecPtrIsValid() instead.
+ */
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L || defined(__cplusplus) && __cplusplus >= 201402L
+[[deprecated("use XLogRecPtrIsValid() instead")]]
+#elif defined(__GNUC__) || defined(__clang__)
+__attribute__((deprecated("use XLogRecPtrIsValid() instead")))
+#elif defined(_MSC_VER)
+__declspec(deprecated("use XLogRecPtrIsValid() instead"))
+#endif
+
+static inline bool
+XLogRecPtrIsInvalid(XLogRecPtr ptr)
+{
+	return ptr == InvalidXLogRecPtr;
+}
+
 /*
  * First LSN to use for "fake" LSNs.
  *
-- 
2.34.1

v2-0003-Replace-InvalidXLogRecPtr-comparisons-with-XLogRe.patchtext/x-diff; charset=us-asciiDownload
From ae4663d5946e713f53fb17663d2ec60012aed4c7 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Wed, 29 Oct 2025 11:45:52 +0000
Subject: [PATCH v2 3/4] Replace InvalidXLogRecPtr comparisons with
 XLogRecPtrIsValid()

This commit ensures the XLogRecPtrIsValid() macro is used instead of direct
InvalidXLogRecPtr equality comparisons.
---
 src/backend/access/heap/rewriteheap.c         |  4 +-
 src/backend/access/transam/twophase.c         |  2 +-
 src/backend/access/transam/xlog.c             | 18 ++++-----
 src/backend/access/transam/xloginsert.c       |  4 +-
 src/backend/access/transam/xlogreader.c       |  2 +-
 src/backend/access/transam/xlogrecovery.c     |  8 ++--
 src/backend/access/transam/xlogutils.c        |  8 ++--
 src/backend/catalog/pg_subscription.c         |  4 +-
 src/backend/replication/logical/logical.c     | 30 +++++++--------
 .../replication/logical/logicalfuncs.c        |  4 +-
 src/backend/replication/logical/origin.c      | 18 ++++-----
 src/backend/replication/logical/proto.c       | 18 ++++-----
 .../replication/logical/reorderbuffer.c       | 38 +++++++++----------
 src/backend/replication/logical/snapbuild.c   | 14 +++----
 src/backend/replication/slot.c                | 18 ++++-----
 src/backend/replication/slotfuncs.c           |  6 +--
 src/backend/replication/walsender.c           |  6 +--
 src/bin/pg_basebackup/pg_receivewal.c         |  6 +--
 src/bin/pg_basebackup/pg_recvlogical.c        | 10 ++---
 src/bin/pg_waldump/pg_waldump.c               |  4 +-
 src/include/access/xlogdefs.h                 |  2 +-
 21 files changed, 112 insertions(+), 112 deletions(-)
  19.5% src/backend/access/transam/
  55.2% src/backend/replication/logical/
  12.4% src/backend/replication/
   7.7% src/bin/pg_basebackup/
   5.0% src/

diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c
index 8061e92f044..66ab48f0fe0 100644
--- a/src/backend/access/heap/rewriteheap.c
+++ b/src/backend/access/heap/rewriteheap.c
@@ -1169,7 +1169,7 @@ CheckPointLogicalRewriteHeap(void)
 	cutoff = ReplicationSlotsComputeLogicalRestartLSN();
 
 	/* don't start earlier than the restart lsn */
-	if (cutoff != InvalidXLogRecPtr && redo < cutoff)
+	if (XLogRecPtrIsValid(cutoff) && redo < cutoff)
 		cutoff = redo;
 
 	mappings_dir = AllocateDir(PG_LOGICAL_MAPPINGS_DIR);
@@ -1204,7 +1204,7 @@ CheckPointLogicalRewriteHeap(void)
 
 		lsn = ((uint64) hi) << 32 | lo;
 
-		if (lsn < cutoff || cutoff == InvalidXLogRecPtr)
+		if (lsn < cutoff || !XLogRecPtrIsValid(cutoff))
 		{
 			elog(DEBUG1, "removing logical rewrite file \"%s\"", path);
 			if (unlink(path) < 0)
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 8a92b292e56..89d0bfa7760 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -2198,7 +2198,7 @@ ProcessTwoPhaseBuffer(FullTransactionId fxid,
 	Assert(LWLockHeldByMeInMode(TwoPhaseStateLock, LW_EXCLUSIVE));
 
 	if (!fromdisk)
-		Assert(prepare_start_lsn != InvalidXLogRecPtr);
+		Assert(XLogRecPtrIsValid(prepare_start_lsn));
 
 	/* Already processed? */
 	if (TransactionIdDidCommit(XidFromFullTransactionId(fxid)) ||
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 4b827c17cfa..b2f53022805 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -848,7 +848,7 @@ XLogInsertRecord(XLogRecData *rdata,
 
 		if (doPageWrites &&
 			(!prevDoPageWrites ||
-			 (fpw_lsn != InvalidXLogRecPtr && fpw_lsn <= RedoRecPtr)))
+			 (XLogRecPtrIsValid(fpw_lsn) && fpw_lsn <= RedoRecPtr)))
 		{
 			/*
 			 * Oops, some buffer now needs to be backed up that the caller
@@ -882,7 +882,7 @@ XLogInsertRecord(XLogRecData *rdata,
 		 * Those checks are only needed for records that can contain buffer
 		 * references, and an XLOG_SWITCH record never does.
 		 */
-		Assert(fpw_lsn == InvalidXLogRecPtr);
+		Assert(!XLogRecPtrIsValid(fpw_lsn));
 		WALInsertLockAcquireExclusive();
 		inserted = ReserveXLogSwitch(&StartPos, &EndPos, &rechdr->xl_prev);
 	}
@@ -897,7 +897,7 @@ XLogInsertRecord(XLogRecData *rdata,
 		 * not check RedoRecPtr before inserting the record; we just need to
 		 * update it afterwards.
 		 */
-		Assert(fpw_lsn == InvalidXLogRecPtr);
+		Assert(!XLogRecPtrIsValid(fpw_lsn));
 		WALInsertLockAcquireExclusive();
 		ReserveXLogInsertLocation(rechdr->xl_tot_len, &StartPos, &EndPos,
 								  &rechdr->xl_prev);
@@ -1602,7 +1602,7 @@ WaitXLogInsertionsToFinish(XLogRecPtr upto)
 			 */
 		} while (insertingat < upto);
 
-		if (insertingat != InvalidXLogRecPtr && insertingat < finishedUpto)
+		if (XLogRecPtrIsValid(insertingat) && insertingat < finishedUpto)
 			finishedUpto = insertingat;
 	}
 
@@ -7356,7 +7356,7 @@ CreateCheckPoint(int flags)
 	 * Update the average distance between checkpoints if the prior checkpoint
 	 * exists.
 	 */
-	if (PriorRedoPtr != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(PriorRedoPtr))
 		UpdateCheckPointDistanceEstimate(RedoRecPtr - PriorRedoPtr);
 
 	INJECTION_POINT("checkpoint-before-old-wal-removal", NULL);
@@ -7804,7 +7804,7 @@ CreateRestartPoint(int flags)
 	 * Update the average distance between checkpoints/restartpoints if the
 	 * prior checkpoint exists.
 	 */
-	if (PriorRedoPtr != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(PriorRedoPtr))
 		UpdateCheckPointDistanceEstimate(RedoRecPtr - PriorRedoPtr);
 
 	/*
@@ -8011,7 +8011,7 @@ KeepLogSeg(XLogRecPtr recptr, XLogSegNo *logSegNo)
 
 	/* Calculate how many segments are kept by slots. */
 	keep = XLogGetReplicationSlotMinimumLSN();
-	if (keep != InvalidXLogRecPtr && keep < recptr)
+	if (XLogRecPtrIsValid(keep) && keep < recptr)
 	{
 		XLByteToSeg(keep, segno, wal_segment_size);
 
@@ -8038,7 +8038,7 @@ KeepLogSeg(XLogRecPtr recptr, XLogSegNo *logSegNo)
 	 * summarized.
 	 */
 	keep = GetOldestUnsummarizedLSN(NULL, NULL);
-	if (keep != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(keep))
 	{
 		XLogSegNo	unsummarized_segno;
 
@@ -8596,7 +8596,7 @@ xlog_redo(XLogReaderState *record)
 			LocalMinRecoveryPoint = ControlFile->minRecoveryPoint;
 			LocalMinRecoveryPointTLI = ControlFile->minRecoveryPointTLI;
 		}
-		if (LocalMinRecoveryPoint != InvalidXLogRecPtr && LocalMinRecoveryPoint < lsn)
+		if (XLogRecPtrIsValid(LocalMinRecoveryPoint) && LocalMinRecoveryPoint < lsn)
 		{
 			TimeLineID	replayTLI;
 
diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c
index 58cb4b1b00c..a56d5a55282 100644
--- a/src/backend/access/transam/xloginsert.c
+++ b/src/backend/access/transam/xloginsert.c
@@ -528,7 +528,7 @@ XLogInsert(RmgrId rmid, uint8 info)
 
 		EndPos = XLogInsertRecord(rdt, fpw_lsn, curinsert_flags, num_fpi,
 								  fpi_bytes, topxid_included);
-	} while (EndPos == InvalidXLogRecPtr);
+	} while (!XLogRecPtrIsValid(EndPos));
 
 	XLogResetInsertion();
 
@@ -639,7 +639,7 @@ XLogRecordAssemble(RmgrId rmid, uint8 info,
 			needs_backup = (page_lsn <= RedoRecPtr);
 			if (!needs_backup)
 			{
-				if (*fpw_lsn == InvalidXLogRecPtr || page_lsn < *fpw_lsn)
+				if (!XLogRecPtrIsValid(*fpw_lsn) || page_lsn < *fpw_lsn)
 					*fpw_lsn = page_lsn;
 			}
 		}
diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index aad16127e60..755f351143a 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -558,7 +558,7 @@ XLogDecodeNextRecord(XLogReaderState *state, bool nonblocking)
 
 	RecPtr = state->NextRecPtr;
 
-	if (state->DecodeRecPtr != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(state->DecodeRecPtr))
 	{
 		/* read the record after the one we just read */
 
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index 84df67b07d2..f1e90076576 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -757,9 +757,9 @@ InitWalRecovery(ControlFileData *ControlFile, bool *wasShutdown_ptr,
 		 * end-of-backup record), and we can enter archive recovery directly.
 		 */
 		if (ArchiveRecoveryRequested &&
-			(ControlFile->minRecoveryPoint != InvalidXLogRecPtr ||
+			(XLogRecPtrIsValid(ControlFile->minRecoveryPoint) ||
 			 ControlFile->backupEndRequired ||
-			 ControlFile->backupEndPoint != InvalidXLogRecPtr ||
+			 XLogRecPtrIsValid(ControlFile->backupEndPoint) ||
 			 ControlFile->state == DB_SHUTDOWNED))
 		{
 			InArchiveRecovery = true;
@@ -3151,7 +3151,7 @@ ReadRecord(XLogPrefetcher *xlogprefetcher, int emode,
 	/* Pass through parameters to XLogPageRead */
 	private->fetching_ckpt = fetching_ckpt;
 	private->emode = emode;
-	private->randAccess = (xlogreader->ReadRecPtr == InvalidXLogRecPtr);
+	private->randAccess = (!XLogRecPtrIsValid(xlogreader->ReadRecPtr));
 	private->replayTLI = replayTLI;
 
 	/* This is the first attempt to read this page. */
@@ -4336,7 +4336,7 @@ XLogFileReadAnyTLI(XLogSegNo segno, XLogSource source)
 		 * Skip scanning the timeline ID that the logfile segment to read
 		 * doesn't belong to
 		 */
-		if (hent->begin != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(hent->begin))
 		{
 			XLogSegNo	beginseg = 0;
 
diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c
index 38176d9688e..ce2a3e42146 100644
--- a/src/backend/access/transam/xlogutils.c
+++ b/src/backend/access/transam/xlogutils.c
@@ -710,7 +710,7 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage,
 	const XLogRecPtr lastReadPage = (state->seg.ws_segno *
 									 state->segcxt.ws_segsize + state->segoff);
 
-	Assert(wantPage != InvalidXLogRecPtr && wantPage % XLOG_BLCKSZ == 0);
+	Assert(XLogRecPtrIsValid(wantPage) && wantPage % XLOG_BLCKSZ == 0);
 	Assert(wantLength <= XLOG_BLCKSZ);
 	Assert(state->readLen == 0 || state->readLen <= XLOG_BLCKSZ);
 	Assert(currTLI != 0);
@@ -741,7 +741,7 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage,
 	 */
 	if (state->currTLI == currTLI && wantPage >= lastReadPage)
 	{
-		Assert(state->currTLIValidUntil == InvalidXLogRecPtr);
+		Assert(!XLogRecPtrIsValid(state->currTLIValidUntil));
 		return;
 	}
 
@@ -750,7 +750,7 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage,
 	 * timeline and the timeline we're reading from is valid until the end of
 	 * the current segment we can just keep reading.
 	 */
-	if (state->currTLIValidUntil != InvalidXLogRecPtr &&
+	if (XLogRecPtrIsValid(state->currTLIValidUntil) &&
 		state->currTLI != currTLI &&
 		state->currTLI != 0 &&
 		((wantPage + wantLength) / state->segcxt.ws_segsize) <
@@ -790,7 +790,7 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage,
 		state->currTLIValidUntil = tliSwitchPoint(state->currTLI, timelineHistory,
 												  &state->nextTLI);
 
-		Assert(state->currTLIValidUntil == InvalidXLogRecPtr ||
+		Assert(!XLogRecPtrIsValid(state->currTLIValidUntil) ||
 			   wantPage + wantLength < state->currTLIValidUntil);
 
 		list_free_deep(timelineHistory);
diff --git a/src/backend/catalog/pg_subscription.c b/src/backend/catalog/pg_subscription.c
index 15b233a37d8..d836ea80b4d 100644
--- a/src/backend/catalog/pg_subscription.c
+++ b/src/backend/catalog/pg_subscription.c
@@ -293,7 +293,7 @@ AddSubscriptionRelState(Oid subid, Oid relid, char state,
 	values[Anum_pg_subscription_rel_srsubid - 1] = ObjectIdGetDatum(subid);
 	values[Anum_pg_subscription_rel_srrelid - 1] = ObjectIdGetDatum(relid);
 	values[Anum_pg_subscription_rel_srsubstate - 1] = CharGetDatum(state);
-	if (sublsn != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(sublsn))
 		values[Anum_pg_subscription_rel_srsublsn - 1] = LSNGetDatum(sublsn);
 	else
 		nulls[Anum_pg_subscription_rel_srsublsn - 1] = true;
@@ -366,7 +366,7 @@ UpdateSubscriptionRelState(Oid subid, Oid relid, char state,
 	values[Anum_pg_subscription_rel_srsubstate - 1] = CharGetDatum(state);
 
 	replaces[Anum_pg_subscription_rel_srsublsn - 1] = true;
-	if (sublsn != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(sublsn))
 		values[Anum_pg_subscription_rel_srsublsn - 1] = LSNGetDatum(sublsn);
 	else
 		nulls[Anum_pg_subscription_rel_srsublsn - 1] = true;
diff --git a/src/backend/replication/logical/logical.c b/src/backend/replication/logical/logical.c
index 79717b52941..866f92cf799 100644
--- a/src/backend/replication/logical/logical.c
+++ b/src/backend/replication/logical/logical.c
@@ -546,9 +546,9 @@ CreateDecodingContext(XLogRecPtr start_lsn,
 
 	/* slot must be valid to allow decoding */
 	Assert(slot->data.invalidated == RS_INVAL_NONE);
-	Assert(slot->data.restart_lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(slot->data.restart_lsn));
 
-	if (start_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(start_lsn))
 	{
 		/* continue from last position */
 		start_lsn = slot->data.confirmed_flush;
@@ -757,7 +757,7 @@ output_plugin_error_callback(void *arg)
 	LogicalErrorCallbackState *state = (LogicalErrorCallbackState *) arg;
 
 	/* not all callbacks have an associated LSN  */
-	if (state->report_location != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(state->report_location))
 		errcontext("slot \"%s\", output plugin \"%s\", in the %s callback, associated LSN %X/%08X",
 				   NameStr(state->ctx->slot->data.name),
 				   NameStr(state->ctx->slot->data.plugin),
@@ -1711,7 +1711,7 @@ LogicalIncreaseXminForSlot(XLogRecPtr current_lsn, TransactionId xmin)
 	 * Only increase if the previous values have been applied, otherwise we
 	 * might never end up updating if the receiver acks too slowly.
 	 */
-	else if (slot->candidate_xmin_lsn == InvalidXLogRecPtr)
+	else if (!XLogRecPtrIsValid(slot->candidate_xmin_lsn))
 	{
 		slot->candidate_catalog_xmin = xmin;
 		slot->candidate_xmin_lsn = current_lsn;
@@ -1749,8 +1749,8 @@ LogicalIncreaseRestartDecodingForSlot(XLogRecPtr current_lsn, XLogRecPtr restart
 	slot = MyReplicationSlot;
 
 	Assert(slot != NULL);
-	Assert(restart_lsn != InvalidXLogRecPtr);
-	Assert(current_lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(restart_lsn));
+	Assert(XLogRecPtrIsValid(current_lsn));
 
 	SpinLockAcquire(&slot->mutex);
 
@@ -1779,7 +1779,7 @@ LogicalIncreaseRestartDecodingForSlot(XLogRecPtr current_lsn, XLogRecPtr restart
 	 * might never end up updating if the receiver acks too slowly. A missed
 	 * value here will just cause some extra effort after reconnecting.
 	 */
-	else if (slot->candidate_restart_valid == InvalidXLogRecPtr)
+	else if (!XLogRecPtrIsValid(slot->candidate_restart_valid))
 	{
 		slot->candidate_restart_valid = current_lsn;
 		slot->candidate_restart_lsn = restart_lsn;
@@ -1819,11 +1819,11 @@ LogicalIncreaseRestartDecodingForSlot(XLogRecPtr current_lsn, XLogRecPtr restart
 void
 LogicalConfirmReceivedLocation(XLogRecPtr lsn)
 {
-	Assert(lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(lsn));
 
 	/* Do an unlocked check for candidate_lsn first. */
-	if (MyReplicationSlot->candidate_xmin_lsn != InvalidXLogRecPtr ||
-		MyReplicationSlot->candidate_restart_valid != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(MyReplicationSlot->candidate_xmin_lsn) ||
+		XLogRecPtrIsValid(MyReplicationSlot->candidate_restart_valid))
 	{
 		bool		updated_xmin = false;
 		bool		updated_restart = false;
@@ -1849,7 +1849,7 @@ LogicalConfirmReceivedLocation(XLogRecPtr lsn)
 			MyReplicationSlot->data.confirmed_flush = lsn;
 
 		/* if we're past the location required for bumping xmin, do so */
-		if (MyReplicationSlot->candidate_xmin_lsn != InvalidXLogRecPtr &&
+		if (XLogRecPtrIsValid(MyReplicationSlot->candidate_xmin_lsn) &&
 			MyReplicationSlot->candidate_xmin_lsn <= lsn)
 		{
 			/*
@@ -1871,10 +1871,10 @@ LogicalConfirmReceivedLocation(XLogRecPtr lsn)
 			}
 		}
 
-		if (MyReplicationSlot->candidate_restart_valid != InvalidXLogRecPtr &&
+		if (XLogRecPtrIsValid(MyReplicationSlot->candidate_restart_valid) &&
 			MyReplicationSlot->candidate_restart_valid <= lsn)
 		{
-			Assert(MyReplicationSlot->candidate_restart_lsn != InvalidXLogRecPtr);
+			Assert(XLogRecPtrIsValid(MyReplicationSlot->candidate_restart_lsn));
 
 			MyReplicationSlot->data.restart_lsn = MyReplicationSlot->candidate_restart_lsn;
 			MyReplicationSlot->candidate_restart_lsn = InvalidXLogRecPtr;
@@ -2089,7 +2089,7 @@ LogicalSlotAdvanceAndCheckSnapState(XLogRecPtr moveto,
 	ResourceOwner old_resowner PG_USED_FOR_ASSERTS_ONLY = CurrentResourceOwner;
 	XLogRecPtr	retlsn;
 
-	Assert(moveto != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(moveto));
 
 	if (found_consistent_snapshot)
 		*found_consistent_snapshot = false;
@@ -2163,7 +2163,7 @@ LogicalSlotAdvanceAndCheckSnapState(XLogRecPtr moveto,
 		if (found_consistent_snapshot && DecodingContextReady(ctx))
 			*found_consistent_snapshot = true;
 
-		if (ctx->reader->EndRecPtr != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(ctx->reader->EndRecPtr))
 		{
 			LogicalConfirmReceivedLocation(moveto);
 
diff --git a/src/backend/replication/logical/logicalfuncs.c b/src/backend/replication/logical/logicalfuncs.c
index d78e486bca6..49b2aef3c74 100644
--- a/src/backend/replication/logical/logicalfuncs.c
+++ b/src/backend/replication/logical/logicalfuncs.c
@@ -276,7 +276,7 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin
 			}
 
 			/* check limits */
-			if (upto_lsn != InvalidXLogRecPtr &&
+			if (XLogRecPtrIsValid(upto_lsn) &&
 				upto_lsn <= ctx->reader->EndRecPtr)
 				break;
 			if (upto_nchanges != 0 &&
@@ -289,7 +289,7 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin
 		 * Next time, start where we left off. (Hunting things, the family
 		 * business..)
 		 */
-		if (ctx->reader->EndRecPtr != InvalidXLogRecPtr && confirm)
+		if (XLogRecPtrIsValid(ctx->reader->EndRecPtr) && confirm)
 		{
 			LogicalConfirmReceivedLocation(ctx->reader->EndRecPtr);
 
diff --git a/src/backend/replication/logical/origin.c b/src/backend/replication/logical/origin.c
index bcd5d9aad62..4632aa8115d 100644
--- a/src/backend/replication/logical/origin.c
+++ b/src/backend/replication/logical/origin.c
@@ -984,8 +984,8 @@ replorigin_advance(RepOriginId node,
 		/* initialize new slot */
 		LWLockAcquire(&free_state->lock, LW_EXCLUSIVE);
 		replication_state = free_state;
-		Assert(replication_state->remote_lsn == InvalidXLogRecPtr);
-		Assert(replication_state->local_lsn == InvalidXLogRecPtr);
+		Assert(!XLogRecPtrIsValid(replication_state->remote_lsn));
+		Assert(!XLogRecPtrIsValid(replication_state->local_lsn));
 		replication_state->roident = node;
 	}
 
@@ -1020,7 +1020,7 @@ replorigin_advance(RepOriginId node,
 	 */
 	if (go_backward || replication_state->remote_lsn < remote_commit)
 		replication_state->remote_lsn = remote_commit;
-	if (local_commit != InvalidXLogRecPtr &&
+	if (XLogRecPtrIsValid(local_commit) &&
 		(go_backward || replication_state->local_lsn < local_commit))
 		replication_state->local_lsn = local_commit;
 	LWLockRelease(&replication_state->lock);
@@ -1064,7 +1064,7 @@ replorigin_get_progress(RepOriginId node, bool flush)
 
 	LWLockRelease(ReplicationOriginLock);
 
-	if (flush && local_lsn != InvalidXLogRecPtr)
+	if (flush && XLogRecPtrIsValid(local_lsn))
 		XLogFlush(local_lsn);
 
 	return remote_lsn;
@@ -1197,8 +1197,8 @@ replorigin_session_setup(RepOriginId node, int acquired_by)
 
 		/* initialize new slot */
 		session_replication_state = &replication_states[free_slot];
-		Assert(session_replication_state->remote_lsn == InvalidXLogRecPtr);
-		Assert(session_replication_state->local_lsn == InvalidXLogRecPtr);
+		Assert(!XLogRecPtrIsValid(session_replication_state->remote_lsn));
+		Assert(!XLogRecPtrIsValid(session_replication_state->local_lsn));
 		session_replication_state->roident = node;
 	}
 
@@ -1282,7 +1282,7 @@ replorigin_session_get_progress(bool flush)
 	local_lsn = session_replication_state->local_lsn;
 	LWLockRelease(&session_replication_state->lock);
 
-	if (flush && local_lsn != InvalidXLogRecPtr)
+	if (flush && XLogRecPtrIsValid(local_lsn))
 		XLogFlush(local_lsn);
 
 	return remote_lsn;
@@ -1454,7 +1454,7 @@ pg_replication_origin_session_progress(PG_FUNCTION_ARGS)
 
 	remote_lsn = replorigin_session_get_progress(flush);
 
-	if (remote_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(remote_lsn))
 		PG_RETURN_NULL();
 
 	PG_RETURN_LSN(remote_lsn);
@@ -1543,7 +1543,7 @@ pg_replication_origin_progress(PG_FUNCTION_ARGS)
 
 	remote_lsn = replorigin_get_progress(roident, flush);
 
-	if (remote_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(remote_lsn))
 		PG_RETURN_NULL();
 
 	PG_RETURN_LSN(remote_lsn);
diff --git a/src/backend/replication/logical/proto.c b/src/backend/replication/logical/proto.c
index ed62888764c..f0a913892b9 100644
--- a/src/backend/replication/logical/proto.c
+++ b/src/backend/replication/logical/proto.c
@@ -64,7 +64,7 @@ logicalrep_read_begin(StringInfo in, LogicalRepBeginData *begin_data)
 {
 	/* read fields */
 	begin_data->final_lsn = pq_getmsgint64(in);
-	if (begin_data->final_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(begin_data->final_lsn))
 		elog(ERROR, "final_lsn not set in begin message");
 	begin_data->committime = pq_getmsgint64(in);
 	begin_data->xid = pq_getmsgint(in, 4);
@@ -135,10 +135,10 @@ logicalrep_read_begin_prepare(StringInfo in, LogicalRepPreparedTxnData *begin_da
 {
 	/* read fields */
 	begin_data->prepare_lsn = pq_getmsgint64(in);
-	if (begin_data->prepare_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(begin_data->prepare_lsn))
 		elog(ERROR, "prepare_lsn not set in begin prepare message");
 	begin_data->end_lsn = pq_getmsgint64(in);
-	if (begin_data->end_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(begin_data->end_lsn))
 		elog(ERROR, "end_lsn not set in begin prepare message");
 	begin_data->prepare_time = pq_getmsgint64(in);
 	begin_data->xid = pq_getmsgint(in, 4);
@@ -207,10 +207,10 @@ logicalrep_read_prepare_common(StringInfo in, char *msgtype,
 
 	/* read fields */
 	prepare_data->prepare_lsn = pq_getmsgint64(in);
-	if (prepare_data->prepare_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(prepare_data->prepare_lsn))
 		elog(ERROR, "prepare_lsn is not set in %s message", msgtype);
 	prepare_data->end_lsn = pq_getmsgint64(in);
-	if (prepare_data->end_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(prepare_data->end_lsn))
 		elog(ERROR, "end_lsn is not set in %s message", msgtype);
 	prepare_data->prepare_time = pq_getmsgint64(in);
 	prepare_data->xid = pq_getmsgint(in, 4);
@@ -274,10 +274,10 @@ logicalrep_read_commit_prepared(StringInfo in, LogicalRepCommitPreparedTxnData *
 
 	/* read fields */
 	prepare_data->commit_lsn = pq_getmsgint64(in);
-	if (prepare_data->commit_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(prepare_data->commit_lsn))
 		elog(ERROR, "commit_lsn is not set in commit prepared message");
 	prepare_data->end_lsn = pq_getmsgint64(in);
-	if (prepare_data->end_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(prepare_data->end_lsn))
 		elog(ERROR, "end_lsn is not set in commit prepared message");
 	prepare_data->commit_time = pq_getmsgint64(in);
 	prepare_data->xid = pq_getmsgint(in, 4);
@@ -333,10 +333,10 @@ logicalrep_read_rollback_prepared(StringInfo in,
 
 	/* read fields */
 	rollback_data->prepare_end_lsn = pq_getmsgint64(in);
-	if (rollback_data->prepare_end_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(rollback_data->prepare_end_lsn))
 		elog(ERROR, "prepare_end_lsn is not set in rollback prepared message");
 	rollback_data->rollback_end_lsn = pq_getmsgint64(in);
-	if (rollback_data->rollback_end_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(rollback_data->rollback_end_lsn))
 		elog(ERROR, "rollback_end_lsn is not set in rollback prepared message");
 	rollback_data->prepare_time = pq_getmsgint64(in);
 	rollback_data->rollback_time = pq_getmsgint64(in);
diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c
index b57aef9916d..eb6a84554b7 100644
--- a/src/backend/replication/logical/reorderbuffer.c
+++ b/src/backend/replication/logical/reorderbuffer.c
@@ -701,7 +701,7 @@ ReorderBufferTXNByXid(ReorderBuffer *rb, TransactionId xid, bool create,
 	{
 		/* initialize the new entry, if creation was requested */
 		Assert(ent != NULL);
-		Assert(lsn != InvalidXLogRecPtr);
+		Assert(XLogRecPtrIsValid(lsn));
 
 		ent->txn = ReorderBufferAllocTXN(rb);
 		ent->txn->xid = xid;
@@ -849,7 +849,7 @@ ReorderBufferQueueChange(ReorderBuffer *rb, TransactionId xid, XLogRecPtr lsn,
 	change->lsn = lsn;
 	change->txn = txn;
 
-	Assert(InvalidXLogRecPtr != lsn);
+	Assert(XLogRecPtrIsValid(lsn));
 	dlist_push_tail(&txn->changes, &change->node);
 	txn->nentries++;
 	txn->nentries_mem++;
@@ -966,14 +966,14 @@ AssertTXNLsnOrder(ReorderBuffer *rb)
 													iter.cur);
 
 		/* start LSN must be set */
-		Assert(cur_txn->first_lsn != InvalidXLogRecPtr);
+		Assert(XLogRecPtrIsValid(cur_txn->first_lsn));
 
 		/* If there is an end LSN, it must be higher than start LSN */
-		if (cur_txn->end_lsn != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(cur_txn->end_lsn))
 			Assert(cur_txn->first_lsn <= cur_txn->end_lsn);
 
 		/* Current initial LSN must be strictly higher than previous */
-		if (prev_first_lsn != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(prev_first_lsn))
 			Assert(prev_first_lsn < cur_txn->first_lsn);
 
 		/* known-as-subtxn txns must not be listed */
@@ -990,10 +990,10 @@ AssertTXNLsnOrder(ReorderBuffer *rb)
 
 		/* base snapshot (and its LSN) must be set */
 		Assert(cur_txn->base_snapshot != NULL);
-		Assert(cur_txn->base_snapshot_lsn != InvalidXLogRecPtr);
+		Assert(XLogRecPtrIsValid(cur_txn->base_snapshot_lsn));
 
 		/* current LSN must be strictly higher than previous */
-		if (prev_base_snap_lsn != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(prev_base_snap_lsn))
 			Assert(prev_base_snap_lsn < cur_txn->base_snapshot_lsn);
 
 		/* known-as-subtxn txns must not be listed */
@@ -1022,11 +1022,11 @@ AssertChangeLsnOrder(ReorderBufferTXN *txn)
 
 		cur_change = dlist_container(ReorderBufferChange, node, iter.cur);
 
-		Assert(txn->first_lsn != InvalidXLogRecPtr);
-		Assert(cur_change->lsn != InvalidXLogRecPtr);
+		Assert(XLogRecPtrIsValid(txn->first_lsn));
+		Assert(XLogRecPtrIsValid(cur_change->lsn));
 		Assert(txn->first_lsn <= cur_change->lsn);
 
-		if (txn->end_lsn != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(txn->end_lsn))
 			Assert(cur_change->lsn <= txn->end_lsn);
 
 		Assert(prev_lsn <= cur_change->lsn);
@@ -1053,7 +1053,7 @@ ReorderBufferGetOldestTXN(ReorderBuffer *rb)
 	txn = dlist_head_element(ReorderBufferTXN, node, &rb->toplevel_by_lsn);
 
 	Assert(!rbtxn_is_known_subxact(txn));
-	Assert(txn->first_lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(txn->first_lsn));
 	return txn;
 }
 
@@ -2276,7 +2276,7 @@ ReorderBufferProcessTXN(ReorderBuffer *rb, ReorderBufferTXN *txn,
 			 * We can't call start stream callback before processing first
 			 * change.
 			 */
-			if (prev_lsn == InvalidXLogRecPtr)
+			if (!XLogRecPtrIsValid(prev_lsn))
 			{
 				if (streaming)
 				{
@@ -2291,7 +2291,7 @@ ReorderBufferProcessTXN(ReorderBuffer *rb, ReorderBufferTXN *txn,
 			 * subtransactions. The changes may have the same LSN due to
 			 * MULTI_INSERT xlog records.
 			 */
-			Assert(prev_lsn == InvalidXLogRecPtr || prev_lsn <= change->lsn);
+			Assert(!XLogRecPtrIsValid(prev_lsn) || prev_lsn <= change->lsn);
 
 			prev_lsn = change->lsn;
 
@@ -2975,7 +2975,7 @@ ReorderBufferPrepare(ReorderBuffer *rb, TransactionId xid,
 	 * have been updated in it by now.
 	 */
 	Assert((txn->txn_flags & RBTXN_PREPARE_STATUS_MASK) == RBTXN_IS_PREPARED);
-	Assert(txn->final_lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(txn->final_lsn));
 
 	txn->gid = pstrdup(gid);
 
@@ -3041,7 +3041,7 @@ ReorderBufferFinishPrepared(ReorderBuffer *rb, TransactionId xid,
 		 */
 		Assert((txn->txn_flags & RBTXN_PREPARE_STATUS_MASK) ==
 			   (RBTXN_IS_PREPARED | RBTXN_SKIPPED_PREPARE));
-		Assert(txn->final_lsn != InvalidXLogRecPtr);
+		Assert(XLogRecPtrIsValid(txn->final_lsn));
 
 		/*
 		 * By this time the txn has the prepare record information and it is
@@ -4552,8 +4552,8 @@ ReorderBufferRestoreChanges(ReorderBuffer *rb, ReorderBufferTXN *txn,
 	dlist_mutable_iter cleanup_iter;
 	File	   *fd = &file->vfd;
 
-	Assert(txn->first_lsn != InvalidXLogRecPtr);
-	Assert(txn->final_lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(txn->first_lsn));
+	Assert(XLogRecPtrIsValid(txn->final_lsn));
 
 	/* free current entries, so we have memory for more */
 	dlist_foreach_modify(cleanup_iter, &txn->changes)
@@ -4860,8 +4860,8 @@ ReorderBufferRestoreCleanup(ReorderBuffer *rb, ReorderBufferTXN *txn)
 	XLogSegNo	cur;
 	XLogSegNo	last;
 
-	Assert(txn->first_lsn != InvalidXLogRecPtr);
-	Assert(txn->final_lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(txn->first_lsn));
+	Assert(XLogRecPtrIsValid(txn->final_lsn));
 
 	XLByteToSeg(txn->first_lsn, first, wal_segment_size);
 	XLByteToSeg(txn->final_lsn, last, wal_segment_size);
diff --git a/src/backend/replication/logical/snapbuild.c b/src/backend/replication/logical/snapbuild.c
index 98ddee20929..6e18baa33cb 100644
--- a/src/backend/replication/logical/snapbuild.c
+++ b/src/backend/replication/logical/snapbuild.c
@@ -1210,7 +1210,7 @@ SnapBuildProcessRunningXacts(SnapBuild *builder, XLogRecPtr lsn, xl_running_xact
 	 * oldest ongoing txn might have started when we didn't yet serialize
 	 * anything because we hadn't reached a consistent state yet.
 	 */
-	if (txn != NULL && txn->restart_decoding_lsn != InvalidXLogRecPtr)
+	if (txn != NULL && XLogRecPtrIsValid(txn->restart_decoding_lsn))
 		LogicalIncreaseRestartDecodingForSlot(lsn, txn->restart_decoding_lsn);
 
 	/*
@@ -1218,8 +1218,8 @@ SnapBuildProcessRunningXacts(SnapBuild *builder, XLogRecPtr lsn, xl_running_xact
 	 * we have one.
 	 */
 	else if (txn == NULL &&
-			 builder->reorder->current_restart_decoding_lsn != InvalidXLogRecPtr &&
-			 builder->last_serialized_snapshot != InvalidXLogRecPtr)
+			 XLogRecPtrIsValid(builder->reorder->current_restart_decoding_lsn) &&
+			 XLogRecPtrIsValid(builder->last_serialized_snapshot))
 		LogicalIncreaseRestartDecodingForSlot(lsn,
 											  builder->last_serialized_snapshot);
 }
@@ -1293,7 +1293,7 @@ SnapBuildFindSnapshot(SnapBuild *builder, XLogRecPtr lsn, xl_running_xacts *runn
 	 */
 	if (running->oldestRunningXid == running->nextXid)
 	{
-		if (builder->start_decoding_at == InvalidXLogRecPtr ||
+		if (!XLogRecPtrIsValid(builder->start_decoding_at) ||
 			builder->start_decoding_at <= lsn)
 			/* can decode everything after this */
 			builder->start_decoding_at = lsn + 1;
@@ -1509,8 +1509,8 @@ SnapBuildSerialize(SnapBuild *builder, XLogRecPtr lsn)
 	struct stat stat_buf;
 	Size		sz;
 
-	Assert(lsn != InvalidXLogRecPtr);
-	Assert(builder->last_serialized_snapshot == InvalidXLogRecPtr ||
+	Assert(XLogRecPtrIsValid(lsn));
+	Assert(!XLogRecPtrIsValid(builder->last_serialized_snapshot) ||
 		   builder->last_serialized_snapshot <= lsn);
 
 	/*
@@ -2029,7 +2029,7 @@ CheckPointSnapBuild(void)
 		lsn = ((uint64) hi) << 32 | lo;
 
 		/* check whether we still need it */
-		if (lsn < cutoff || cutoff == InvalidXLogRecPtr)
+		if (lsn < cutoff || !XLogRecPtrIsValid(cutoff))
 		{
 			elog(DEBUG1, "removing snapbuild snapshot %s", path);
 
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index 0cb93dc90f2..1ec1e997b27 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -1270,15 +1270,15 @@ ReplicationSlotsComputeRequiredLSN(void)
 		 */
 		if (persistency == RS_PERSISTENT)
 		{
-			if (last_saved_restart_lsn != InvalidXLogRecPtr &&
+			if (XLogRecPtrIsValid(last_saved_restart_lsn) &&
 				restart_lsn > last_saved_restart_lsn)
 			{
 				restart_lsn = last_saved_restart_lsn;
 			}
 		}
 
-		if (restart_lsn != InvalidXLogRecPtr &&
-			(min_required == InvalidXLogRecPtr ||
+		if (XLogRecPtrIsValid(restart_lsn) &&
+			(!XLogRecPtrIsValid(min_required) ||
 			 restart_lsn < min_required))
 			min_required = restart_lsn;
 	}
@@ -1350,17 +1350,17 @@ ReplicationSlotsComputeLogicalRestartLSN(void)
 		 */
 		if (persistency == RS_PERSISTENT)
 		{
-			if (last_saved_restart_lsn != InvalidXLogRecPtr &&
+			if (XLogRecPtrIsValid(last_saved_restart_lsn) &&
 				restart_lsn > last_saved_restart_lsn)
 			{
 				restart_lsn = last_saved_restart_lsn;
 			}
 		}
 
-		if (restart_lsn == InvalidXLogRecPtr)
+		if (!XLogRecPtrIsValid(restart_lsn))
 			continue;
 
-		if (result == InvalidXLogRecPtr ||
+		if (!XLogRecPtrIsValid(result) ||
 			restart_lsn < result)
 			result = restart_lsn;
 	}
@@ -1573,8 +1573,8 @@ ReplicationSlotReserveWal(void)
 	ReplicationSlot *slot = MyReplicationSlot;
 
 	Assert(slot != NULL);
-	Assert(slot->data.restart_lsn == InvalidXLogRecPtr);
-	Assert(slot->last_saved_restart_lsn == InvalidXLogRecPtr);
+	Assert(!XLogRecPtrIsValid(slot->data.restart_lsn));
+	Assert(!XLogRecPtrIsValid(slot->last_saved_restart_lsn));
 
 	/*
 	 * The replication slot mechanism is used to prevent removal of required
@@ -1754,7 +1754,7 @@ DetermineSlotInvalidationCause(uint32 possible_causes, ReplicationSlot *s,
 	{
 		XLogRecPtr	restart_lsn = s->data.restart_lsn;
 
-		if (restart_lsn != InvalidXLogRecPtr &&
+		if (XLogRecPtrIsValid(restart_lsn) &&
 			restart_lsn < oldestLSN)
 			return RS_INVAL_WAL_REMOVED;
 	}
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 5aecd5c6a50..0478fc9c977 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -308,12 +308,12 @@ pg_get_replication_slots(PG_FUNCTION_ARGS)
 		else
 			nulls[i++] = true;
 
-		if (slot_contents.data.restart_lsn != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(slot_contents.data.restart_lsn))
 			values[i++] = LSNGetDatum(slot_contents.data.restart_lsn);
 		else
 			nulls[i++] = true;
 
-		if (slot_contents.data.confirmed_flush != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(slot_contents.data.confirmed_flush))
 			values[i++] = LSNGetDatum(slot_contents.data.confirmed_flush);
 		else
 			nulls[i++] = true;
@@ -467,7 +467,7 @@ pg_physical_replication_slot_advance(XLogRecPtr moveto)
 	XLogRecPtr	startlsn = MyReplicationSlot->data.restart_lsn;
 	XLogRecPtr	retlsn = startlsn;
 
-	Assert(moveto != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(moveto));
 
 	if (startlsn < moveto)
 	{
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index b6dfb230d0d..4a678e60b74 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -2397,7 +2397,7 @@ PhysicalConfirmReceivedLocation(XLogRecPtr lsn)
 	bool		changed = false;
 	ReplicationSlot *slot = MyReplicationSlot;
 
-	Assert(lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(lsn));
 	SpinLockAcquire(&slot->mutex);
 	if (slot->data.restart_lsn != lsn)
 	{
@@ -2519,7 +2519,7 @@ ProcessStandbyReplyMessage(void)
 	/*
 	 * Advance our local xmin horizon when the client confirmed a flush.
 	 */
-	if (MyReplicationSlot && flushPtr != InvalidXLogRecPtr)
+	if (MyReplicationSlot && XLogRecPtrIsValid(flushPtr))
 	{
 		if (SlotIsLogical(MyReplicationSlot))
 			LogicalConfirmReceivedLocation(flushPtr);
@@ -3536,7 +3536,7 @@ XLogSendLogical(void)
 	 * If first time through in this session, initialize flushPtr.  Otherwise,
 	 * we only need to update flushPtr if EndRecPtr is past it.
 	 */
-	if (flushPtr == InvalidXLogRecPtr ||
+	if (!XLogRecPtrIsValid(flushPtr) ||
 		logical_decoding_ctx->reader->EndRecPtr >= flushPtr)
 	{
 		/*
diff --git a/src/bin/pg_basebackup/pg_receivewal.c b/src/bin/pg_basebackup/pg_receivewal.c
index 3e6f4a7fc48..46e553dce4b 100644
--- a/src/bin/pg_basebackup/pg_receivewal.c
+++ b/src/bin/pg_basebackup/pg_receivewal.c
@@ -535,7 +535,7 @@ StreamLog(void)
 	 * Figure out where to start streaming.  First scan the local directory.
 	 */
 	stream.startpos = FindStreamingStart(&stream.timeline);
-	if (stream.startpos == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(stream.startpos))
 	{
 		/*
 		 * Try to get the starting point from the slot if any.  This is
@@ -556,14 +556,14 @@ StreamLog(void)
 		 * If it the starting point is still not known, use the current WAL
 		 * flush value as last resort.
 		 */
-		if (stream.startpos == InvalidXLogRecPtr)
+		if (!XLogRecPtrIsValid(stream.startpos))
 		{
 			stream.startpos = serverpos;
 			stream.timeline = servertli;
 		}
 	}
 
-	Assert(stream.startpos != InvalidXLogRecPtr &&
+	Assert(XLogRecPtrIsValid(stream.startpos) &&
 		   stream.timeline != 0);
 
 	/*
diff --git a/src/bin/pg_basebackup/pg_recvlogical.c b/src/bin/pg_basebackup/pg_recvlogical.c
index 6739784a993..14ad1504678 100644
--- a/src/bin/pg_basebackup/pg_recvlogical.c
+++ b/src/bin/pg_basebackup/pg_recvlogical.c
@@ -482,7 +482,7 @@ StreamLogicalLog(void)
 			}
 			replyRequested = copybuf[pos];
 
-			if (endpos != InvalidXLogRecPtr && walEnd >= endpos)
+			if (XLogRecPtrIsValid(endpos) && walEnd >= endpos)
 			{
 				/*
 				 * If there's nothing to read on the socket until a keepalive
@@ -535,7 +535,7 @@ StreamLogicalLog(void)
 		/* Extract WAL location for this block */
 		cur_record_lsn = fe_recvint64(&copybuf[1]);
 
-		if (endpos != InvalidXLogRecPtr && cur_record_lsn > endpos)
+		if (XLogRecPtrIsValid(endpos) && cur_record_lsn > endpos)
 		{
 			/*
 			 * We've read past our endpoint, so prepare to go away being
@@ -583,7 +583,7 @@ StreamLogicalLog(void)
 			goto error;
 		}
 
-		if (endpos != InvalidXLogRecPtr && cur_record_lsn == endpos)
+		if (XLogRecPtrIsValid(endpos) && cur_record_lsn == endpos)
 		{
 			/* endpos was exactly the record we just processed, we're done */
 			if (!flushAndSendFeedback(conn, &now))
@@ -913,14 +913,14 @@ main(int argc, char **argv)
 		exit(1);
 	}
 
-	if (startpos != InvalidXLogRecPtr && (do_create_slot || do_drop_slot))
+	if (XLogRecPtrIsValid(startpos) && (do_create_slot || do_drop_slot))
 	{
 		pg_log_error("cannot use --create-slot or --drop-slot together with --startpos");
 		pg_log_error_hint("Try \"%s --help\" for more information.", progname);
 		exit(1);
 	}
 
-	if (endpos != InvalidXLogRecPtr && !do_start_slot)
+	if (XLogRecPtrIsValid(endpos) && !do_start_slot)
 	{
 		pg_log_error("--endpos may only be specified with --start");
 		pg_log_error_hint("Try \"%s --help\" for more information.", progname);
diff --git a/src/bin/pg_waldump/pg_waldump.c b/src/bin/pg_waldump/pg_waldump.c
index 19cf5461eac..c6d6ba79e44 100644
--- a/src/bin/pg_waldump/pg_waldump.c
+++ b/src/bin/pg_waldump/pg_waldump.c
@@ -393,7 +393,7 @@ WALDumpReadPage(XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen,
 	int			count = XLOG_BLCKSZ;
 	WALReadError errinfo;
 
-	if (private->endptr != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(private->endptr))
 	{
 		if (targetPagePtr + XLOG_BLCKSZ <= private->endptr)
 			count = XLOG_BLCKSZ;
@@ -1213,7 +1213,7 @@ main(int argc, char **argv)
 	/* first find a valid recptr to start from */
 	first_record = XLogFindNextRecord(xlogreader_state, private.startptr);
 
-	if (first_record == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(first_record))
 		pg_fatal("could not find a valid record after %X/%08X",
 				 LSN_FORMAT_ARGS(private.startptr));
 
diff --git a/src/include/access/xlogdefs.h b/src/include/access/xlogdefs.h
index 6eebf86342e..eba50dd7297 100644
--- a/src/include/access/xlogdefs.h
+++ b/src/include/access/xlogdefs.h
@@ -44,7 +44,7 @@ __declspec(deprecated("use XLogRecPtrIsValid() instead"))
 static inline bool
 XLogRecPtrIsInvalid(XLogRecPtr ptr)
 {
-	return ptr == InvalidXLogRecPtr;
+	return !XLogRecPtrIsValid(ptr);
 }
 
 /*
-- 
2.34.1

v2-0004-Replace-literal-0-comparisons-on-XLogRecPtr-with-.patchtext/x-diff; charset=us-asciiDownload
From 071e0550cf787e991316e3c2c487199cdaae9f56 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Wed, 29 Oct 2025 18:46:28 +0000
Subject: [PATCH v2 4/4] Replace literal 0 comparisons on XLogRecPtr with
 XLogRecPtrIsValid()

This commit ensures the XLogRecPtrIsValid() macro is used instead of direct
literal 0 comparisons on XLogRecPtr.
---
 src/backend/access/transam/xlogfuncs.c     | 4 ++--
 src/backend/replication/walreceiverfuncs.c | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)
  42.3% src/backend/access/transam/
  57.6% src/backend/replication/

diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index 8c3090165f0..3e45fce43ed 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -341,7 +341,7 @@ pg_last_wal_receive_lsn(PG_FUNCTION_ARGS)
 
 	recptr = GetWalRcvFlushRecPtr(NULL, NULL);
 
-	if (recptr == 0)
+	if (!XLogRecPtrIsValid(recptr))
 		PG_RETURN_NULL();
 
 	PG_RETURN_LSN(recptr);
@@ -360,7 +360,7 @@ pg_last_wal_replay_lsn(PG_FUNCTION_ARGS)
 
 	recptr = GetXLogReplayRecPtr(NULL);
 
-	if (recptr == 0)
+	if (!XLogRecPtrIsValid(recptr))
 		PG_RETURN_NULL();
 
 	PG_RETURN_LSN(recptr);
diff --git a/src/backend/replication/walreceiverfuncs.c b/src/backend/replication/walreceiverfuncs.c
index 8de2886ff0b..f447ded2d07 100644
--- a/src/backend/replication/walreceiverfuncs.c
+++ b/src/backend/replication/walreceiverfuncs.c
@@ -301,7 +301,7 @@ RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, const char *conninfo,
 	 * If this is the first startup of walreceiver (on this timeline),
 	 * initialize flushedUpto and latestChunkStart to the starting point.
 	 */
-	if (walrcv->receiveStart == 0 || walrcv->receivedTLI != tli)
+	if (!XLogRecPtrIsValid(walrcv->receiveStart) || walrcv->receivedTLI != tli)
 	{
 		walrcv->flushedUpto = recptr;
 		walrcv->receivedTLI = tli;
-- 
2.34.1

#10Bertrand Drouvot
bertranddrouvot.pg@gmail.com
In reply to: Peter Eisentraut (#8)
Re: Consistently use the XLogRecPtrIsInvalid() macro

Hi,

On Wed, Oct 29, 2025 at 05:50:13PM +0100, Peter Eisentraut wrote:

On 28.10.25 13:33, Bertrand Drouvot wrote:

I do prefer to introduce XLogRecPtrIsValid(x) and switch to that. Then, do the
same kind of work on OidIsValid() and TransactionIdIsValid() and add an annual
check.

Idea is to get some code consistency while keeping macros which are valuable for
readability and centralize changes if any need to be done in the way we check
their validity.

If we wanted real type safety, we could turn XLogRecPtr back into a struct,
and then enforce the use of XLogRecPtrIsValid() and similar.

Right. That said I think that we'd need an opaque struct to avoid developers
doing things like: lsn.value == InvalidXLogRecPtr. If not, we'd still
need regular checks to ensure the macro is used. Opaque struct would probably
add extra costs too.

Otherwise, we
should just acknowledge that it's an integer and use integer code to deal
with it. These *IsValid() and similar macros that are there for
"readability" but are not actually enforced other than by some developers'
willpower are just causing more work and inconsistency in the long run.

That's a good point. Scripts (like the ones shared in [1]) can catch violations,
but it's still "manual" enforcement.

We don't currently enforce the other *IsValid() macros. I think it would be worth
setting up checks for all of them, but I agree that's new ongoing maintenance
work.

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

#11Peter Eisentraut
peter@eisentraut.org
In reply to: Bertrand Drouvot (#9)
Re: Consistently use the XLogRecPtrIsInvalid() macro

On 30.10.25 10:17, Bertrand Drouvot wrote:

- 0002 deprecates XLogRecPtrIsInvalid(): it emits a warning message at compilation
time if XLogRecPtrIsInvalid() is in use in the code base.

Surely this could be factored out in macro in such a way that the
warning message is a macro argument and we could reuse this attribute
elsewhere in the code.

That said, I'm suspicious about marking things deprecated before the
replacement is widely available. If an extension has been using
XLogRecPtrIsInvalid() until now (which has been best practice), when
that extension adds PG19 support, they will either have to backport
XLogRecPtrIsValid or turn off deprecation warnings. At least there
should be some guidance about what you expect third-party code to do
about this.

#12Bertrand Drouvot
bertranddrouvot.pg@gmail.com
In reply to: Peter Eisentraut (#11)
Re: Consistently use the XLogRecPtrIsInvalid() macro

Hi,

On Thu, Oct 30, 2025 at 02:55:51PM +0100, Peter Eisentraut wrote:

On 30.10.25 10:17, Bertrand Drouvot wrote:

- 0002 deprecates XLogRecPtrIsInvalid(): it emits a warning message at compilation
time if XLogRecPtrIsInvalid() is in use in the code base.

Surely this could be factored out in macro in such a way that the warning
message is a macro argument and we could reuse this attribute elsewhere in
the code.

Yeah, I thought about it and initially considered waiting until we have another
use case. But you're right that it's better to do it from the start.

That said, I'm suspicious about marking things deprecated before the
replacement is widely available. If an extension has been using
XLogRecPtrIsInvalid() until now (which has been best practice), when that
extension adds PG19 support, they will either have to backport
XLogRecPtrIsValid or turn off deprecation warnings.

That's a good point, thanks! I agree with your concern.

After giving it more thought, I'm inclined to postpone the compiler warning
until XLogRecPtrIsValid() has been available for some time. The question is for
how long?

I did some research, reading [1]/messages/by-id/4992828D.8000307@gmx.net (but that's not really identical) or looking
at what we did for example for "SPI_prepare_cursor", "SPI_prepare_params"
and friends (but again that's not really identical): 844fe9f159a mentioned
that they "can perhaps go away at some point" and are documented as
deprecated since PG14.

So, back at our case, a conservative approach would be to wait for 5
years until the new macro is available on all the supported major versions.
That would mean introduce the deprecated attribute in PG24.

I don't see waiting for PG24 as an issue: the main goal of the new macro is
to be consistent with other *IsValid() ones and avoid "double negation" and that
would be achieved in the core code base.

For PG19, we could:

Add a comment in the code documenting that XLogRecPtrIsInvalid() is deprecated
and that we will enforce a "deprecated" attribute on it in PG24.

At least there should
be some guidance about what you expect third-party code to do about this.

The alternative of adding the warning immediately with migration guidance would
still create "friction". Especially if we deprecate multiple APIs following this
new pattern (i.e adding a "deprecated" attribute). As you said, they could
backport the macro themselves but that seems like unnecessary friction when we
can simply wait.

What do you think?

[1]: /messages/by-id/4992828D.8000307@gmx.net

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

#13Peter Eisentraut
peter@eisentraut.org
In reply to: Bertrand Drouvot (#12)
Re: Consistently use the XLogRecPtrIsInvalid() macro

On 31.10.25 05:31, Bertrand Drouvot wrote:

For PG19, we could:

Add a comment in the code documenting that XLogRecPtrIsInvalid() is deprecated
and that we will enforce a "deprecated" attribute on it in PG24.

Just a code comment for now seems reasonable. I wouldn't make any
predictions about the future in code comments, though.

#14Bertrand Drouvot
bertranddrouvot.pg@gmail.com
In reply to: Peter Eisentraut (#13)
3 attachment(s)
Re: Consistently use the XLogRecPtrIsInvalid() macro

Hi,

On Fri, Oct 31, 2025 at 08:41:46AM +0100, Peter Eisentraut wrote:

On 31.10.25 05:31, Bertrand Drouvot wrote:

For PG19, we could:

Add a comment in the code documenting that XLogRecPtrIsInvalid() is deprecated
and that we will enforce a "deprecated" attribute on it in PG24.

Just a code comment for now seems reasonable. I wouldn't make any
predictions about the future in code comments, though.

Done that way in 0001 attached.

Also in passing I realized that v2 did miss doing a replacement:

"PageGetLSN(page) == InvalidXLogRecPtr" in vacuumlazy.c.

I changed it "manually" for now in 0002 and checked that no other replacements
is missing.

Will fix the associated coccinelle script.

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

Attachments:

v3-0001-Introduce-XLogRecPtrIsValid-and-replace-XLogRecPt.patchtext/x-diff; charset=us-asciiDownload
From 18a19f6c7ca19d98296c0659eb38170072421401 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Wed, 29 Oct 2025 10:34:03 +0000
Subject: [PATCH v3 1/3] Introduce XLogRecPtrIsValid() and replace
 XLogRecPtrIsInvalid() calls

XLogRecPtrIsInvalid() is inconsistent with the affirmative form of other
*IsValid() macros and leads to awkward double negative.

This commit introduces XLogRecPtrIsValid() and replace all the
XLogRecPtrIsInvalid() calls.

It also adds a comment mentioning that new code should use XLogRecPtrIsValid()
instead of XLogRecPtrIsInvalid() and that XLogRecPtrIsInvalid() could be
deprecated in the future.
---
 contrib/pg_walinspect/pg_walinspect.c         |  4 +--
 src/backend/access/gist/gist.c                |  4 +--
 src/backend/access/gist/gistget.c             |  4 +--
 src/backend/access/gist/gistutil.c            |  2 +-
 src/backend/access/heap/visibilitymap.c       |  4 +--
 src/backend/access/transam/clog.c             |  5 ++--
 src/backend/access/transam/slru.c             |  2 +-
 src/backend/access/transam/timeline.c         |  4 +--
 src/backend/access/transam/twophase.c         |  4 +--
 src/backend/access/transam/xlog.c             | 30 +++++++++----------
 src/backend/access/transam/xlogbackup.c       |  4 +--
 src/backend/access/transam/xlogreader.c       |  6 ++--
 src/backend/access/transam/xlogrecovery.c     | 12 ++++----
 src/backend/backup/backup_manifest.c          |  4 +--
 src/backend/backup/basebackup_incremental.c   |  2 +-
 src/backend/backup/walsummary.c               |  8 ++---
 src/backend/commands/subscriptioncmds.c       |  6 ++--
 src/backend/postmaster/walsummarizer.c        | 18 +++++------
 .../replication/logical/applyparallelworker.c |  4 +--
 src/backend/replication/logical/launcher.c    |  4 +--
 src/backend/replication/logical/logical.c     |  2 +-
 .../replication/logical/logicalfuncs.c        |  2 +-
 src/backend/replication/logical/slotsync.c    |  6 ++--
 src/backend/replication/logical/worker.c      | 16 +++++-----
 src/backend/replication/slot.c                | 10 +++----
 src/backend/replication/slotfuncs.c           | 16 +++++-----
 src/backend/replication/syncrep.c             | 10 +++----
 src/backend/replication/walreceiver.c         |  8 ++---
 src/backend/replication/walsender.c           | 22 +++++++-------
 src/backend/storage/buffer/bufmgr.c           |  2 +-
 src/bin/pg_basebackup/pg_receivewal.c         |  2 +-
 src/bin/pg_basebackup/pg_recvlogical.c        |  2 +-
 src/bin/pg_rewind/pg_rewind.c                 |  4 +--
 src/bin/pg_waldump/pg_waldump.c               | 10 +++----
 src/include/access/xlogdefs.h                 | 10 ++++++-
 35 files changed, 131 insertions(+), 122 deletions(-)
   4.2% src/backend/access/gist/
  26.7% src/backend/access/transam/
   6.4% src/backend/backup/
   7.6% src/backend/postmaster/
  14.0% src/backend/replication/logical/
  26.2% src/backend/replication/
   4.1% src/backend/
   3.7% src/bin/pg_waldump/
   5.2% src/

diff --git a/contrib/pg_walinspect/pg_walinspect.c b/contrib/pg_walinspect/pg_walinspect.c
index 501cea8fc1a..3c5e4a856a7 100644
--- a/contrib/pg_walinspect/pg_walinspect.c
+++ b/contrib/pg_walinspect/pg_walinspect.c
@@ -83,7 +83,7 @@ GetCurrentLSN(void)
 	else
 		curr_lsn = GetXLogReplayRecPtr(NULL);
 
-	Assert(!XLogRecPtrIsInvalid(curr_lsn));
+	Assert(XLogRecPtrIsValid(curr_lsn));
 
 	return curr_lsn;
 }
@@ -127,7 +127,7 @@ InitXLogReaderState(XLogRecPtr lsn)
 	/* first find a valid recptr to start from */
 	first_valid_record = XLogFindNextRecord(xlogreader, lsn);
 
-	if (XLogRecPtrIsInvalid(first_valid_record))
+	if (!XLogRecPtrIsValid(first_valid_record))
 		ereport(ERROR,
 				errmsg("could not find a valid record after %X/%08X",
 					   LSN_FORMAT_ARGS(lsn)));
diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c
index 5213cd71e97..3fb1a1285c5 100644
--- a/src/backend/access/gist/gist.c
+++ b/src/backend/access/gist/gist.c
@@ -682,7 +682,7 @@ gistdoinsert(Relation r, IndexTuple itup, Size freespace,
 			state.stack = stack = stack->parent;
 		}
 
-		if (XLogRecPtrIsInvalid(stack->lsn))
+		if (!XLogRecPtrIsValid(stack->lsn))
 			stack->buffer = ReadBuffer(state.r, stack->blkno);
 
 		/*
@@ -698,7 +698,7 @@ gistdoinsert(Relation r, IndexTuple itup, Size freespace,
 		stack->page = BufferGetPage(stack->buffer);
 		stack->lsn = xlocked ?
 			PageGetLSN(stack->page) : BufferGetLSNAtomic(stack->buffer);
-		Assert(!RelationNeedsWAL(state.r) || !XLogRecPtrIsInvalid(stack->lsn));
+		Assert(!RelationNeedsWAL(state.r) || XLogRecPtrIsValid(stack->lsn));
 
 		/*
 		 * If this page was split but the downlink was never inserted to the
diff --git a/src/backend/access/gist/gistget.c b/src/backend/access/gist/gistget.c
index 387d9972345..9ba45acfff3 100644
--- a/src/backend/access/gist/gistget.c
+++ b/src/backend/access/gist/gistget.c
@@ -46,7 +46,7 @@ gistkillitems(IndexScanDesc scan)
 	bool		killedsomething = false;
 
 	Assert(so->curBlkno != InvalidBlockNumber);
-	Assert(!XLogRecPtrIsInvalid(so->curPageLSN));
+	Assert(XLogRecPtrIsValid(so->curPageLSN));
 	Assert(so->killedItems != NULL);
 
 	buffer = ReadBuffer(scan->indexRelation, so->curBlkno);
@@ -353,7 +353,7 @@ gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem,
 	 * parentlsn < nsn), or if the system crashed after a page split but
 	 * before the downlink was inserted into the parent.
 	 */
-	if (!XLogRecPtrIsInvalid(pageItem->data.parentlsn) &&
+	if (XLogRecPtrIsValid(pageItem->data.parentlsn) &&
 		(GistFollowRight(page) ||
 		 pageItem->data.parentlsn < GistPageGetNSN(page)) &&
 		opaque->rightlink != InvalidBlockNumber /* sanity check */ )
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index 98b79608341..75272827837 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -1040,7 +1040,7 @@ gistGetFakeLSN(Relation rel)
 		Assert(!RelationNeedsWAL(rel));
 
 		/* No need for an actual record if we already have a distinct LSN */
-		if (!XLogRecPtrIsInvalid(lastlsn) && lastlsn == currlsn)
+		if (XLogRecPtrIsValid(lastlsn) && lastlsn == currlsn)
 			currlsn = gistXLogAssignLSN();
 
 		lastlsn = currlsn;
diff --git a/src/backend/access/heap/visibilitymap.c b/src/backend/access/heap/visibilitymap.c
index 2f5e61e2392..d14588e92ae 100644
--- a/src/backend/access/heap/visibilitymap.c
+++ b/src/backend/access/heap/visibilitymap.c
@@ -260,7 +260,7 @@ visibilitymap_set(Relation rel, BlockNumber heapBlk, Buffer heapBuf,
 		 flags, RelationGetRelationName(rel), heapBlk);
 #endif
 
-	Assert(InRecovery || XLogRecPtrIsInvalid(recptr));
+	Assert(InRecovery || !XLogRecPtrIsValid(recptr));
 	Assert(InRecovery || PageIsAllVisible(BufferGetPage(heapBuf)));
 	Assert((flags & VISIBILITYMAP_VALID_BITS) == flags);
 
@@ -292,7 +292,7 @@ visibilitymap_set(Relation rel, BlockNumber heapBlk, Buffer heapBuf,
 
 		if (RelationNeedsWAL(rel))
 		{
-			if (XLogRecPtrIsInvalid(recptr))
+			if (!XLogRecPtrIsValid(recptr))
 			{
 				Assert(!InRecovery);
 				recptr = log_heap_visible(rel, heapBuf, vmBuf, cutoff_xid, flags);
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index e80fbe109cf..ea43b432daf 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -381,7 +381,8 @@ TransactionIdSetPageStatusInternal(TransactionId xid, int nsubxids,
 	 * write-busy, since we don't care if the update reaches disk sooner than
 	 * we think.
 	 */
-	slotno = SimpleLruReadPage(XactCtl, pageno, XLogRecPtrIsInvalid(lsn), xid);
+	slotno = SimpleLruReadPage(XactCtl, pageno, !XLogRecPtrIsValid(lsn),
+							   xid);
 
 	/*
 	 * Set the main transaction id, if any.
@@ -705,7 +706,7 @@ TransactionIdSetStatusBit(TransactionId xid, XidStatus status, XLogRecPtr lsn, i
 	 * recovery. After recovery completes the next clog change will set the
 	 * LSN correctly.
 	 */
-	if (!XLogRecPtrIsInvalid(lsn))
+	if (XLogRecPtrIsValid(lsn))
 	{
 		int			lsnindex = GetLSNIndex(slotno, xid);
 
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index 5d3fcd62c94..77676d6d035 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -937,7 +937,7 @@ SlruPhysicalWritePage(SlruCtl ctl, int64 pageno, int slotno, SlruWriteAll fdata)
 				max_lsn = this_lsn;
 		}
 
-		if (!XLogRecPtrIsInvalid(max_lsn))
+		if (XLogRecPtrIsValid(max_lsn))
 		{
 			/*
 			 * As noted above, elog(ERROR) is not acceptable here, so if
diff --git a/src/backend/access/transam/timeline.c b/src/backend/access/transam/timeline.c
index 186eb91f609..ec3e323ec0c 100644
--- a/src/backend/access/transam/timeline.c
+++ b/src/backend/access/transam/timeline.c
@@ -549,8 +549,8 @@ tliOfPointInHistory(XLogRecPtr ptr, List *history)
 	{
 		TimeLineHistoryEntry *tle = (TimeLineHistoryEntry *) lfirst(cell);
 
-		if ((XLogRecPtrIsInvalid(tle->begin) || tle->begin <= ptr) &&
-			(XLogRecPtrIsInvalid(tle->end) || ptr < tle->end))
+		if ((!XLogRecPtrIsValid(tle->begin) || tle->begin <= ptr) &&
+			(!XLogRecPtrIsValid(tle->end) || ptr < tle->end))
 		{
 			/* found it */
 			return tle->tli;
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 33369fbe23a..8a92b292e56 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -2547,7 +2547,7 @@ PrepareRedoAdd(FullTransactionId fxid, char *buf,
 	 * the record is added to TwoPhaseState and it should have no
 	 * corresponding file in pg_twophase.
 	 */
-	if (!XLogRecPtrIsInvalid(start_lsn))
+	if (XLogRecPtrIsValid(start_lsn))
 	{
 		char		path[MAXPGPATH];
 
@@ -2587,7 +2587,7 @@ PrepareRedoAdd(FullTransactionId fxid, char *buf,
 	gxact->owner = hdr->owner;
 	gxact->locking_backend = INVALID_PROC_NUMBER;
 	gxact->valid = false;
-	gxact->ondisk = XLogRecPtrIsInvalid(start_lsn);
+	gxact->ondisk = !XLogRecPtrIsValid(start_lsn);
 	gxact->inredo = true;		/* yes, added in redo */
 	strcpy(gxact->gid, gid);
 
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index fd91bcd68ec..4b827c17cfa 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -1761,7 +1761,7 @@ WALReadFromBuffers(char *dstbuf, XLogRecPtr startptr, Size count,
 	if (RecoveryInProgress() || tli != GetWALInsertionTimeLine())
 		return 0;
 
-	Assert(!XLogRecPtrIsInvalid(startptr));
+	Assert(XLogRecPtrIsValid(startptr));
 
 	/*
 	 * Caller should ensure that the requested data has been inserted into WAL
@@ -2716,7 +2716,7 @@ UpdateMinRecoveryPoint(XLogRecPtr lsn, bool force)
 	 * available is replayed in this case.  This also saves from extra locks
 	 * taken on the control file from the startup process.
 	 */
-	if (XLogRecPtrIsInvalid(LocalMinRecoveryPoint) && InRecovery)
+	if (!XLogRecPtrIsValid(LocalMinRecoveryPoint) && InRecovery)
 	{
 		updateMinRecoveryPoint = false;
 		return;
@@ -2728,7 +2728,7 @@ UpdateMinRecoveryPoint(XLogRecPtr lsn, bool force)
 	LocalMinRecoveryPoint = ControlFile->minRecoveryPoint;
 	LocalMinRecoveryPointTLI = ControlFile->minRecoveryPointTLI;
 
-	if (XLogRecPtrIsInvalid(LocalMinRecoveryPoint))
+	if (!XLogRecPtrIsValid(LocalMinRecoveryPoint))
 		updateMinRecoveryPoint = false;
 	else if (force || LocalMinRecoveryPoint < lsn)
 	{
@@ -3148,7 +3148,7 @@ XLogNeedsFlush(XLogRecPtr record)
 		 * which cannot update its local copy of minRecoveryPoint as long as
 		 * it has not replayed all WAL available when doing crash recovery.
 		 */
-		if (XLogRecPtrIsInvalid(LocalMinRecoveryPoint) && InRecovery)
+		if (!XLogRecPtrIsValid(LocalMinRecoveryPoint) && InRecovery)
 		{
 			updateMinRecoveryPoint = false;
 			return false;
@@ -3169,7 +3169,7 @@ XLogNeedsFlush(XLogRecPtr record)
 		 * process doing crash recovery, which should not update the control
 		 * file value if crash recovery is still running.
 		 */
-		if (XLogRecPtrIsInvalid(LocalMinRecoveryPoint))
+		if (!XLogRecPtrIsValid(LocalMinRecoveryPoint))
 			updateMinRecoveryPoint = false;
 
 		/* check again */
@@ -5934,7 +5934,7 @@ StartupXLOG(void)
 	 */
 	if (InRecovery &&
 		(EndOfLog < LocalMinRecoveryPoint ||
-		 !XLogRecPtrIsInvalid(ControlFile->backupStartPoint)))
+		 XLogRecPtrIsValid(ControlFile->backupStartPoint)))
 	{
 		/*
 		 * Ran off end of WAL before reaching end-of-backup WAL record, or
@@ -5944,7 +5944,7 @@ StartupXLOG(void)
 		 */
 		if (ArchiveRecoveryRequested || ControlFile->backupEndRequired)
 		{
-			if (!XLogRecPtrIsInvalid(ControlFile->backupStartPoint) || ControlFile->backupEndRequired)
+			if (XLogRecPtrIsValid(ControlFile->backupStartPoint) || ControlFile->backupEndRequired)
 				ereport(FATAL,
 						(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 						 errmsg("WAL ends before end of online backup"),
@@ -6046,7 +6046,7 @@ StartupXLOG(void)
 	 * (It's critical to first write an OVERWRITE_CONTRECORD message, which
 	 * we'll do as soon as we're open for writing new WAL.)
 	 */
-	if (!XLogRecPtrIsInvalid(missingContrecPtr))
+	if (XLogRecPtrIsValid(missingContrecPtr))
 	{
 		/*
 		 * We should only have a missingContrecPtr if we're not switching to a
@@ -6056,7 +6056,7 @@ StartupXLOG(void)
 		 * disregard.
 		 */
 		Assert(newTLI == endOfRecoveryInfo->lastRecTLI);
-		Assert(!XLogRecPtrIsInvalid(abortedRecPtr));
+		Assert(XLogRecPtrIsValid(abortedRecPtr));
 		EndOfLog = missingContrecPtr;
 	}
 
@@ -6160,9 +6160,9 @@ StartupXLOG(void)
 	LocalSetXLogInsertAllowed();
 
 	/* If necessary, write overwrite-contrecord before doing anything else */
-	if (!XLogRecPtrIsInvalid(abortedRecPtr))
+	if (XLogRecPtrIsValid(abortedRecPtr))
 	{
-		Assert(!XLogRecPtrIsInvalid(missingContrecPtr));
+		Assert(XLogRecPtrIsValid(missingContrecPtr));
 		CreateOverwriteContrecordRecord(abortedRecPtr, missingContrecPtr, newTLI);
 	}
 
@@ -7686,7 +7686,7 @@ CreateRestartPoint(int flags)
 	 * restartpoint. It's assumed that flushing the buffers will do that as a
 	 * side-effect.
 	 */
-	if (XLogRecPtrIsInvalid(lastCheckPointRecPtr) ||
+	if (!XLogRecPtrIsValid(lastCheckPointRecPtr) ||
 		lastCheckPoint.redo <= ControlFile->checkPointCopy.redo)
 	{
 		ereport(DEBUG2,
@@ -7929,7 +7929,7 @@ GetWALAvailability(XLogRecPtr targetLSN)
 	/*
 	 * slot does not reserve WAL. Either deactivated, or has never been active
 	 */
-	if (XLogRecPtrIsInvalid(targetLSN))
+	if (!XLogRecPtrIsValid(targetLSN))
 		return WALAVAIL_INVALID_LSN;
 
 	/*
@@ -8345,8 +8345,8 @@ xlog_redo(XLogReaderState *record)
 		 * never arrive.
 		 */
 		if (ArchiveRecoveryRequested &&
-			!XLogRecPtrIsInvalid(ControlFile->backupStartPoint) &&
-			XLogRecPtrIsInvalid(ControlFile->backupEndPoint))
+			XLogRecPtrIsValid(ControlFile->backupStartPoint) &&
+			!XLogRecPtrIsValid(ControlFile->backupEndPoint))
 			ereport(PANIC,
 					(errmsg("online backup was canceled, recovery cannot continue")));
 
diff --git a/src/backend/access/transam/xlogbackup.c b/src/backend/access/transam/xlogbackup.c
index cda4b38b7d6..78908ea32b3 100644
--- a/src/backend/access/transam/xlogbackup.c
+++ b/src/backend/access/transam/xlogbackup.c
@@ -78,8 +78,8 @@ build_backup_content(BackupState *state, bool ishistoryfile)
 	}
 
 	/* either both istartpoint and istarttli should be set, or neither */
-	Assert(XLogRecPtrIsInvalid(state->istartpoint) == (state->istarttli == 0));
-	if (!XLogRecPtrIsInvalid(state->istartpoint))
+	Assert(!XLogRecPtrIsValid(state->istartpoint) == (state->istarttli == 0));
+	if (XLogRecPtrIsValid(state->istartpoint))
 	{
 		appendStringInfo(result, "INCREMENTAL FROM LSN: %X/%08X\n",
 						 LSN_FORMAT_ARGS(state->istartpoint));
diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index dcc8d4f9c1b..aad16127e60 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -231,7 +231,7 @@ WALOpenSegmentInit(WALOpenSegment *seg, WALSegmentContext *segcxt,
 void
 XLogBeginRead(XLogReaderState *state, XLogRecPtr RecPtr)
 {
-	Assert(!XLogRecPtrIsInvalid(RecPtr));
+	Assert(XLogRecPtrIsValid(RecPtr));
 
 	ResetDecoder(state);
 
@@ -343,7 +343,7 @@ XLogNextRecord(XLogReaderState *state, char **errormsg)
 		 * XLogBeginRead() or XLogNextRecord(), and is the location of the
 		 * error.
 		 */
-		Assert(!XLogRecPtrIsInvalid(state->EndRecPtr));
+		Assert(XLogRecPtrIsValid(state->EndRecPtr));
 
 		return NULL;
 	}
@@ -1398,7 +1398,7 @@ XLogFindNextRecord(XLogReaderState *state, XLogRecPtr RecPtr)
 	XLogPageHeader header;
 	char	   *errormsg;
 
-	Assert(!XLogRecPtrIsInvalid(RecPtr));
+	Assert(XLogRecPtrIsValid(RecPtr));
 
 	/* Make sure ReadPageInternal() can't return XLREAD_WOULDBLOCK. */
 	state->nonblocking = false;
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index 3e3c4da01a2..84df67b07d2 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -772,7 +772,7 @@ InitWalRecovery(ControlFileData *ControlFile, bool *wasShutdown_ptr,
 		 * emit a log message when we continue initializing from a base
 		 * backup.
 		 */
-		if (!XLogRecPtrIsInvalid(ControlFile->backupStartPoint))
+		if (XLogRecPtrIsValid(ControlFile->backupStartPoint))
 			ereport(LOG,
 					errmsg("restarting backup recovery with redo LSN %X/%08X",
 						   LSN_FORMAT_ARGS(ControlFile->backupStartPoint)));
@@ -867,7 +867,7 @@ InitWalRecovery(ControlFileData *ControlFile, bool *wasShutdown_ptr,
 	 * The min recovery point should be part of the requested timeline's
 	 * history, too.
 	 */
-	if (!XLogRecPtrIsInvalid(ControlFile->minRecoveryPoint) &&
+	if (XLogRecPtrIsValid(ControlFile->minRecoveryPoint) &&
 		tliOfPointInHistory(ControlFile->minRecoveryPoint - 1, expectedTLEs) !=
 		ControlFile->minRecoveryPointTLI)
 		ereport(FATAL,
@@ -2193,7 +2193,7 @@ CheckRecoveryConsistency(void)
 	 * During crash recovery, we don't reach a consistent state until we've
 	 * replayed all the WAL.
 	 */
-	if (XLogRecPtrIsInvalid(minRecoveryPoint))
+	if (!XLogRecPtrIsValid(minRecoveryPoint))
 		return;
 
 	Assert(InArchiveRecovery);
@@ -2208,7 +2208,7 @@ CheckRecoveryConsistency(void)
 	/*
 	 * Have we reached the point where our base backup was completed?
 	 */
-	if (!XLogRecPtrIsInvalid(backupEndPoint) &&
+	if (XLogRecPtrIsValid(backupEndPoint) &&
 		backupEndPoint <= lastReplayedEndRecPtr)
 	{
 		XLogRecPtr	saveBackupStartPoint = backupStartPoint;
@@ -2414,7 +2414,7 @@ checkTimeLineSwitch(XLogRecPtr lsn, TimeLineID newTLI, TimeLineID prevTLI,
 	 * branched before the timeline the min recovery point is on, and you
 	 * attempt to do PITR to the new timeline.
 	 */
-	if (!XLogRecPtrIsInvalid(minRecoveryPoint) &&
+	if (XLogRecPtrIsValid(minRecoveryPoint) &&
 		lsn < minRecoveryPoint &&
 		newTLI > minRecoveryPointTLI)
 		ereport(PANIC,
@@ -3177,7 +3177,7 @@ ReadRecord(XLogPrefetcher *xlogprefetcher, int emode,
 			 * overwrite contrecord in the wrong place, breaking everything.
 			 */
 			if (!ArchiveRecoveryRequested &&
-				!XLogRecPtrIsInvalid(xlogreader->abortedRecPtr))
+				XLogRecPtrIsValid(xlogreader->abortedRecPtr))
 			{
 				abortedRecPtr = xlogreader->abortedRecPtr;
 				missingContrecPtr = xlogreader->missingContrecPtr;
diff --git a/src/backend/backup/backup_manifest.c b/src/backend/backup/backup_manifest.c
index d05252f383c..dd76c9b0b63 100644
--- a/src/backend/backup/backup_manifest.c
+++ b/src/backend/backup/backup_manifest.c
@@ -242,7 +242,7 @@ AddWALInfoToBackupManifest(backup_manifest_info *manifest, XLogRecPtr startptr,
 		 * entry->end is InvalidXLogRecPtr, it means that the timeline has not
 		 * yet ended.)
 		 */
-		if (!XLogRecPtrIsInvalid(entry->end) && entry->end < startptr)
+		if (XLogRecPtrIsValid(entry->end) && entry->end < startptr)
 			continue;
 
 		/*
@@ -274,7 +274,7 @@ AddWALInfoToBackupManifest(backup_manifest_info *manifest, XLogRecPtr startptr,
 			 * better have arrived at the expected starting TLI. If not,
 			 * something's gone horribly wrong.
 			 */
-			if (XLogRecPtrIsInvalid(entry->begin))
+			if (!XLogRecPtrIsValid(entry->begin))
 				ereport(ERROR,
 						errmsg("expected start timeline %u but found timeline %u",
 							   starttli, entry->tli));
diff --git a/src/backend/backup/basebackup_incremental.c b/src/backend/backup/basebackup_incremental.c
index a0d48ff0fef..852ab577045 100644
--- a/src/backend/backup/basebackup_incremental.c
+++ b/src/backend/backup/basebackup_incremental.c
@@ -519,7 +519,7 @@ PrepareForIncrementalBackup(IncrementalBackupInfo *ib,
 		if (!WalSummariesAreComplete(tli_wslist, tli_start_lsn, tli_end_lsn,
 									 &tli_missing_lsn))
 		{
-			if (XLogRecPtrIsInvalid(tli_missing_lsn))
+			if (!XLogRecPtrIsValid(tli_missing_lsn))
 				ereport(ERROR,
 						(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 						 errmsg("WAL summaries are required on timeline %u from %X/%08X to %X/%08X, but no summaries for that timeline and LSN range exist",
diff --git a/src/backend/backup/walsummary.c b/src/backend/backup/walsummary.c
index c7a2c65cc6a..2689eae3328 100644
--- a/src/backend/backup/walsummary.c
+++ b/src/backend/backup/walsummary.c
@@ -67,9 +67,9 @@ GetWalSummaries(TimeLineID tli, XLogRecPtr start_lsn, XLogRecPtr end_lsn)
 		/* Skip if it doesn't match the filter criteria. */
 		if (tli != 0 && tli != file_tli)
 			continue;
-		if (!XLogRecPtrIsInvalid(start_lsn) && start_lsn >= file_end_lsn)
+		if (XLogRecPtrIsValid(start_lsn) && start_lsn >= file_end_lsn)
 			continue;
-		if (!XLogRecPtrIsInvalid(end_lsn) && end_lsn <= file_start_lsn)
+		if (XLogRecPtrIsValid(end_lsn) && end_lsn <= file_start_lsn)
 			continue;
 
 		/* Add it to the list. */
@@ -111,9 +111,9 @@ FilterWalSummaries(List *wslist, TimeLineID tli,
 		/* Skip if it doesn't match the filter criteria. */
 		if (tli != 0 && tli != ws->tli)
 			continue;
-		if (!XLogRecPtrIsInvalid(start_lsn) && start_lsn > ws->end_lsn)
+		if (XLogRecPtrIsValid(start_lsn) && start_lsn > ws->end_lsn)
 			continue;
-		if (!XLogRecPtrIsInvalid(end_lsn) && end_lsn < ws->start_lsn)
+		if (XLogRecPtrIsValid(end_lsn) && end_lsn < ws->start_lsn)
 			continue;
 
 		/* Add it to the result list. */
diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c
index 1f45444b499..ccf238f665b 100644
--- a/src/backend/commands/subscriptioncmds.c
+++ b/src/backend/commands/subscriptioncmds.c
@@ -393,7 +393,7 @@ parse_subscription_options(ParseState *pstate, List *stmt_options,
 				lsn = DatumGetLSN(DirectFunctionCall1(pg_lsn_in,
 													  CStringGetDatum(lsn_str)));
 
-				if (XLogRecPtrIsInvalid(lsn))
+				if (!XLogRecPtrIsValid(lsn))
 					ereport(ERROR,
 							(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 							 errmsg("invalid WAL location (LSN): %s", lsn_str)));
@@ -1893,7 +1893,7 @@ AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt,
 				 * If the user sets subskiplsn, we do a sanity check to make
 				 * sure that the specified LSN is a probable value.
 				 */
-				if (!XLogRecPtrIsInvalid(opts.lsn))
+				if (XLogRecPtrIsValid(opts.lsn))
 				{
 					RepOriginId originid;
 					char		originname[NAMEDATALEN];
@@ -1905,7 +1905,7 @@ AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt,
 					remote_lsn = replorigin_get_progress(originid, false);
 
 					/* Check the given LSN is at least a future LSN */
-					if (!XLogRecPtrIsInvalid(remote_lsn) && opts.lsn < remote_lsn)
+					if (XLogRecPtrIsValid(remote_lsn) && opts.lsn < remote_lsn)
 						ereport(ERROR,
 								(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 								 errmsg("skip WAL location (LSN %X/%08X) must be greater than origin LSN %X/%08X",
diff --git a/src/backend/postmaster/walsummarizer.c b/src/backend/postmaster/walsummarizer.c
index e1f142f20c7..c4a888a081c 100644
--- a/src/backend/postmaster/walsummarizer.c
+++ b/src/backend/postmaster/walsummarizer.c
@@ -342,7 +342,7 @@ WalSummarizerMain(const void *startup_data, size_t startup_data_len)
 	 * If we discover that WAL summarization is not enabled, just exit.
 	 */
 	current_lsn = GetOldestUnsummarizedLSN(&current_tli, &exact);
-	if (XLogRecPtrIsInvalid(current_lsn))
+	if (!XLogRecPtrIsValid(current_lsn))
 		proc_exit(0);
 
 	/*
@@ -379,7 +379,7 @@ WalSummarizerMain(const void *startup_data, size_t startup_data_len)
 		 * only have to do this once per timeline switch, we probably wouldn't
 		 * save any significant amount of work in practice.
 		 */
-		if (current_tli != latest_tli && XLogRecPtrIsInvalid(switch_lsn))
+		if (current_tli != latest_tli && !XLogRecPtrIsValid(switch_lsn))
 		{
 			List	   *tles = readTimeLineHistory(latest_tli);
 
@@ -394,7 +394,7 @@ WalSummarizerMain(const void *startup_data, size_t startup_data_len)
 		 * on this timeline. Switch to the next timeline and go around again,
 		 * backing up to the exact switch point if we passed it.
 		 */
-		if (!XLogRecPtrIsInvalid(switch_lsn) && current_lsn >= switch_lsn)
+		if (XLogRecPtrIsValid(switch_lsn) && current_lsn >= switch_lsn)
 		{
 			/* Restart summarization from switch point. */
 			current_tli = switch_tli;
@@ -419,7 +419,7 @@ WalSummarizerMain(const void *startup_data, size_t startup_data_len)
 		end_of_summary_lsn = SummarizeWAL(current_tli,
 										  current_lsn, exact,
 										  switch_lsn, latest_lsn);
-		Assert(!XLogRecPtrIsInvalid(end_of_summary_lsn));
+		Assert(XLogRecPtrIsValid(end_of_summary_lsn));
 		Assert(end_of_summary_lsn >= current_lsn);
 
 		/*
@@ -923,7 +923,7 @@ SummarizeWAL(TimeLineID tli, XLogRecPtr start_lsn, bool exact,
 	private_data = (SummarizerReadLocalXLogPrivate *)
 		palloc0(sizeof(SummarizerReadLocalXLogPrivate));
 	private_data->tli = tli;
-	private_data->historic = !XLogRecPtrIsInvalid(switch_lsn);
+	private_data->historic = XLogRecPtrIsValid(switch_lsn);
 	private_data->read_upto = maximum_lsn;
 
 	/* Create xlogreader. */
@@ -971,7 +971,7 @@ SummarizeWAL(TimeLineID tli, XLogRecPtr start_lsn, bool exact,
 	else
 	{
 		summary_start_lsn = XLogFindNextRecord(xlogreader, start_lsn);
-		if (XLogRecPtrIsInvalid(summary_start_lsn))
+		if (!XLogRecPtrIsValid(summary_start_lsn))
 		{
 			/*
 			 * If we hit end-of-WAL while trying to find the next valid
@@ -1058,7 +1058,7 @@ SummarizeWAL(TimeLineID tli, XLogRecPtr start_lsn, bool exact,
 		/* We shouldn't go backward. */
 		Assert(summary_start_lsn <= xlogreader->EndRecPtr);
 
-		if (!XLogRecPtrIsInvalid(switch_lsn) &&
+		if (XLogRecPtrIsValid(switch_lsn) &&
 			xlogreader->ReadRecPtr >= switch_lsn)
 		{
 			/*
@@ -1180,7 +1180,7 @@ SummarizeWAL(TimeLineID tli, XLogRecPtr start_lsn, bool exact,
 		 * If we have a switch LSN and have reached it, stop before reading
 		 * the next record.
 		 */
-		if (!XLogRecPtrIsInvalid(switch_lsn) &&
+		if (XLogRecPtrIsValid(switch_lsn) &&
 			xlogreader->EndRecPtr >= switch_lsn)
 			break;
 	}
@@ -1723,7 +1723,7 @@ MaybeRemoveOldWalSummaries(void)
 			 * If the WAL doesn't exist any more, we can remove it if the file
 			 * modification time is old enough.
 			 */
-			if (XLogRecPtrIsInvalid(oldest_lsn) || ws->end_lsn <= oldest_lsn)
+			if (!XLogRecPtrIsValid(oldest_lsn) || ws->end_lsn <= oldest_lsn)
 				RemoveWalSummaryIfOlderThan(ws, cutoff_time);
 
 			/*
diff --git a/src/backend/replication/logical/applyparallelworker.c b/src/backend/replication/logical/applyparallelworker.c
index 14325581afc..baa68c1ab6c 100644
--- a/src/backend/replication/logical/applyparallelworker.c
+++ b/src/backend/replication/logical/applyparallelworker.c
@@ -299,7 +299,7 @@ pa_can_start(void)
 	 * STREAM START message, and it doesn't seem worth sending the extra eight
 	 * bytes with the STREAM START to enable parallelism for this case.
 	 */
-	if (!XLogRecPtrIsInvalid(MySubscription->skiplsn))
+	if (XLogRecPtrIsValid(MySubscription->skiplsn))
 		return false;
 
 	/*
@@ -1640,7 +1640,7 @@ pa_xact_finish(ParallelApplyWorkerInfo *winfo, XLogRecPtr remote_lsn)
 	 */
 	pa_wait_for_xact_finish(winfo);
 
-	if (!XLogRecPtrIsInvalid(remote_lsn))
+	if (XLogRecPtrIsValid(remote_lsn))
 		store_flush_position(remote_lsn, winfo->shared->last_commit_end);
 
 	pa_free_worker(winfo);
diff --git a/src/backend/replication/logical/launcher.c b/src/backend/replication/logical/launcher.c
index 95b5cae9a55..d735114bc59 100644
--- a/src/backend/replication/logical/launcher.c
+++ b/src/backend/replication/logical/launcher.c
@@ -1621,7 +1621,7 @@ pg_stat_get_subscription(PG_FUNCTION_ARGS)
 		else
 			nulls[3] = true;
 
-		if (XLogRecPtrIsInvalid(worker.last_lsn))
+		if (!XLogRecPtrIsValid(worker.last_lsn))
 			nulls[4] = true;
 		else
 			values[4] = LSNGetDatum(worker.last_lsn);
@@ -1633,7 +1633,7 @@ pg_stat_get_subscription(PG_FUNCTION_ARGS)
 			nulls[6] = true;
 		else
 			values[6] = TimestampTzGetDatum(worker.last_recv_time);
-		if (XLogRecPtrIsInvalid(worker.reply_lsn))
+		if (!XLogRecPtrIsValid(worker.reply_lsn))
 			nulls[7] = true;
 		else
 			values[7] = LSNGetDatum(worker.reply_lsn);
diff --git a/src/backend/replication/logical/logical.c b/src/backend/replication/logical/logical.c
index 93ed2eb368e..79717b52941 100644
--- a/src/backend/replication/logical/logical.c
+++ b/src/backend/replication/logical/logical.c
@@ -388,7 +388,7 @@ CreateInitDecodingContext(const char *plugin,
 	slot->data.plugin = plugin_name;
 	SpinLockRelease(&slot->mutex);
 
-	if (XLogRecPtrIsInvalid(restart_lsn))
+	if (!XLogRecPtrIsValid(restart_lsn))
 		ReplicationSlotReserveWal();
 	else
 	{
diff --git a/src/backend/replication/logical/logicalfuncs.c b/src/backend/replication/logical/logicalfuncs.c
index 25f890ddeed..d78e486bca6 100644
--- a/src/backend/replication/logical/logicalfuncs.c
+++ b/src/backend/replication/logical/logicalfuncs.c
@@ -229,7 +229,7 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin
 		 * Wait for specified streaming replication standby servers (if any)
 		 * to confirm receipt of WAL up to wait_for_wal_lsn.
 		 */
-		if (XLogRecPtrIsInvalid(upto_lsn))
+		if (!XLogRecPtrIsValid(upto_lsn))
 			wait_for_wal_lsn = end_of_wal;
 		else
 			wait_for_wal_lsn = Min(upto_lsn, end_of_wal);
diff --git a/src/backend/replication/logical/slotsync.c b/src/backend/replication/logical/slotsync.c
index b122d99b009..8b4afd87dc9 100644
--- a/src/backend/replication/logical/slotsync.c
+++ b/src/backend/replication/logical/slotsync.c
@@ -493,7 +493,7 @@ reserve_wal_for_local_slot(XLogRecPtr restart_lsn)
 	ReplicationSlot *slot = MyReplicationSlot;
 
 	Assert(slot != NULL);
-	Assert(XLogRecPtrIsInvalid(slot->data.restart_lsn));
+	Assert(!XLogRecPtrIsValid(slot->data.restart_lsn));
 
 	while (true)
 	{
@@ -899,8 +899,8 @@ synchronize_slots(WalReceiverConn *wrconn)
 		 * pg_replication_slots view, then we can avoid fetching RS_EPHEMERAL
 		 * slots in the first place.
 		 */
-		if ((XLogRecPtrIsInvalid(remote_slot->restart_lsn) ||
-			 XLogRecPtrIsInvalid(remote_slot->confirmed_lsn) ||
+		if ((!XLogRecPtrIsValid(remote_slot->restart_lsn) ||
+			 !XLogRecPtrIsValid(remote_slot->confirmed_lsn) ||
 			 !TransactionIdIsValid(remote_slot->catalog_xmin)) &&
 			remote_slot->invalidated == RS_INVAL_NONE)
 			pfree(remote_slot);
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index 7edd1c9cf06..e6da007b460 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -514,7 +514,7 @@ bool		InitializingApplyWorker = false;
  * by the user.
  */
 static XLogRecPtr skip_xact_finish_lsn = InvalidXLogRecPtr;
-#define is_skipping_changes() (unlikely(!XLogRecPtrIsInvalid(skip_xact_finish_lsn)))
+#define is_skipping_changes() (unlikely(XLogRecPtrIsValid(skip_xact_finish_lsn)))
 
 /* BufFile handle of the current streaming file */
 static BufFile *stream_fd = NULL;
@@ -4103,7 +4103,7 @@ LogicalRepApplyLoop(XLogRecPtr last_received)
 						 * due to a bug, we don't want to proceed as it can
 						 * incorrectly advance oldest_nonremovable_xid.
 						 */
-						if (XLogRecPtrIsInvalid(rdt_data.remote_lsn))
+						if (!XLogRecPtrIsValid(rdt_data.remote_lsn))
 							elog(ERROR, "cannot get the latest WAL position from the publisher");
 
 						maybe_advance_nonremovable_xid(&rdt_data, true);
@@ -4587,7 +4587,7 @@ wait_for_publisher_status(RetainDeadTuplesData *rdt_data,
 static void
 wait_for_local_flush(RetainDeadTuplesData *rdt_data)
 {
-	Assert(!XLogRecPtrIsInvalid(rdt_data->remote_lsn) &&
+	Assert(XLogRecPtrIsValid(rdt_data->remote_lsn) &&
 		   TransactionIdIsValid(rdt_data->candidate_xid));
 
 	/*
@@ -5993,7 +5993,7 @@ maybe_start_skipping_changes(XLogRecPtr finish_lsn)
 	 * function is called for every remote transaction and we assume that
 	 * skipping the transaction is not used often.
 	 */
-	if (likely(XLogRecPtrIsInvalid(MySubscription->skiplsn) ||
+	if (likely(!XLogRecPtrIsValid(MySubscription->skiplsn) ||
 			   MySubscription->skiplsn != finish_lsn))
 		return;
 
@@ -6039,7 +6039,7 @@ clear_subscription_skip_lsn(XLogRecPtr finish_lsn)
 	XLogRecPtr	myskiplsn = MySubscription->skiplsn;
 	bool		started_tx = false;
 
-	if (likely(XLogRecPtrIsInvalid(myskiplsn)) || am_parallel_apply_worker())
+	if (likely(!XLogRecPtrIsValid(myskiplsn)) || am_parallel_apply_worker())
 		return;
 
 	if (!IsTransactionState())
@@ -6135,7 +6135,7 @@ apply_error_callback(void *arg)
 			errcontext("processing remote data for replication origin \"%s\" during message type \"%s\"",
 					   errarg->origin_name,
 					   logicalrep_message_type(errarg->command));
-		else if (XLogRecPtrIsInvalid(errarg->finish_lsn))
+		else if (!XLogRecPtrIsValid(errarg->finish_lsn))
 			errcontext("processing remote data for replication origin \"%s\" during message type \"%s\" in transaction %u",
 					   errarg->origin_name,
 					   logicalrep_message_type(errarg->command),
@@ -6151,7 +6151,7 @@ apply_error_callback(void *arg)
 	{
 		if (errarg->remote_attnum < 0)
 		{
-			if (XLogRecPtrIsInvalid(errarg->finish_lsn))
+			if (!XLogRecPtrIsValid(errarg->finish_lsn))
 				errcontext("processing remote data for replication origin \"%s\" during message type \"%s\" for replication target relation \"%s.%s\" in transaction %u",
 						   errarg->origin_name,
 						   logicalrep_message_type(errarg->command),
@@ -6169,7 +6169,7 @@ apply_error_callback(void *arg)
 		}
 		else
 		{
-			if (XLogRecPtrIsInvalid(errarg->finish_lsn))
+			if (!XLogRecPtrIsValid(errarg->finish_lsn))
 				errcontext("processing remote data for replication origin \"%s\" during message type \"%s\" for replication target relation \"%s.%s\" column \"%s\" in transaction %u",
 						   errarg->origin_name,
 						   logicalrep_message_type(errarg->command),
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index 6363030808f..0cb93dc90f2 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -1730,7 +1730,7 @@ static inline bool
 CanInvalidateIdleSlot(ReplicationSlot *s)
 {
 	return (idle_replication_slot_timeout_secs != 0 &&
-			!XLogRecPtrIsInvalid(s->data.restart_lsn) &&
+			XLogRecPtrIsValid(s->data.restart_lsn) &&
 			s->inactive_since > 0 &&
 			!(RecoveryInProgress() && s->data.synced));
 }
@@ -2922,7 +2922,7 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
 	 * Don't need to wait for the standbys to catch up if they are already
 	 * beyond the specified WAL location.
 	 */
-	if (!XLogRecPtrIsInvalid(ss_oldest_flush_lsn) &&
+	if (XLogRecPtrIsValid(ss_oldest_flush_lsn) &&
 		ss_oldest_flush_lsn >= wait_for_lsn)
 		return true;
 
@@ -2993,7 +2993,7 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
 			break;
 		}
 
-		if (XLogRecPtrIsInvalid(restart_lsn) || restart_lsn < wait_for_lsn)
+		if (!XLogRecPtrIsValid(restart_lsn) || restart_lsn < wait_for_lsn)
 		{
 			/* Log a message if no active_pid for this physical slot */
 			if (inactive)
@@ -3012,7 +3012,7 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
 
 		Assert(restart_lsn >= wait_for_lsn);
 
-		if (XLogRecPtrIsInvalid(min_restart_lsn) ||
+		if (!XLogRecPtrIsValid(min_restart_lsn) ||
 			min_restart_lsn > restart_lsn)
 			min_restart_lsn = restart_lsn;
 
@@ -3031,7 +3031,7 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
 		return false;
 
 	/* The ss_oldest_flush_lsn must not retreat. */
-	Assert(XLogRecPtrIsInvalid(ss_oldest_flush_lsn) ||
+	Assert(!XLogRecPtrIsValid(ss_oldest_flush_lsn) ||
 		   min_restart_lsn >= ss_oldest_flush_lsn);
 
 	ss_oldest_flush_lsn = min_restart_lsn;
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index b8f21153e7b..5aecd5c6a50 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -46,7 +46,7 @@ create_physical_replication_slot(char *name, bool immediately_reserve,
 	if (immediately_reserve)
 	{
 		/* Reserve WAL as the user asked for it */
-		if (XLogRecPtrIsInvalid(restart_lsn))
+		if (!XLogRecPtrIsValid(restart_lsn))
 			ReplicationSlotReserveWal();
 		else
 			MyReplicationSlot->data.restart_lsn = restart_lsn;
@@ -357,7 +357,7 @@ pg_get_replication_slots(PG_FUNCTION_ARGS)
 				 *
 				 * If we do change it, save the state for safe_wal_size below.
 				 */
-				if (!XLogRecPtrIsInvalid(slot_contents.data.restart_lsn))
+				if (XLogRecPtrIsValid(slot_contents.data.restart_lsn))
 				{
 					int			pid;
 
@@ -407,7 +407,7 @@ pg_get_replication_slots(PG_FUNCTION_ARGS)
 		values[i++] = BoolGetDatum(slot_contents.data.two_phase);
 
 		if (slot_contents.data.two_phase &&
-			!XLogRecPtrIsInvalid(slot_contents.data.two_phase_at))
+			XLogRecPtrIsValid(slot_contents.data.two_phase_at))
 			values[i++] = LSNGetDatum(slot_contents.data.two_phase_at);
 		else
 			nulls[i++] = true;
@@ -523,7 +523,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 
 	CheckSlotPermissions();
 
-	if (XLogRecPtrIsInvalid(moveto))
+	if (!XLogRecPtrIsValid(moveto))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("invalid target WAL LSN")));
@@ -545,7 +545,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	ReplicationSlotAcquire(NameStr(*slotname), true, true);
 
 	/* A slot whose restart_lsn has never been reserved cannot be advanced */
-	if (XLogRecPtrIsInvalid(MyReplicationSlot->data.restart_lsn))
+	if (!XLogRecPtrIsValid(MyReplicationSlot->data.restart_lsn))
 		ereport(ERROR,
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 				 errmsg("replication slot \"%s\" cannot be advanced",
@@ -679,7 +679,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 						NameStr(*src_name))));
 
 	/* Copying non-reserved slot doesn't make sense */
-	if (XLogRecPtrIsInvalid(src_restart_lsn))
+	if (!XLogRecPtrIsValid(src_restart_lsn))
 		ereport(ERROR,
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 				 errmsg("cannot copy a replication slot that doesn't reserve WAL")));
@@ -785,7 +785,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 					 errdetail("The source replication slot was modified incompatibly during the copy operation.")));
 
 		/* The source slot must have a consistent snapshot */
-		if (src_islogical && XLogRecPtrIsInvalid(copy_confirmed_flush))
+		if (src_islogical && !XLogRecPtrIsValid(copy_confirmed_flush))
 			ereport(ERROR,
 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 					 errmsg("cannot copy unfinished logical replication slot \"%s\"",
@@ -840,7 +840,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 	/* All done.  Set up the return values */
 	values[0] = NameGetDatum(dst_name);
 	nulls[0] = false;
-	if (!XLogRecPtrIsInvalid(MyReplicationSlot->data.confirmed_flush))
+	if (XLogRecPtrIsValid(MyReplicationSlot->data.confirmed_flush))
 	{
 		values[1] = LSNGetDatum(MyReplicationSlot->data.confirmed_flush);
 		nulls[1] = false;
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index 32cf3a48b89..a0c79958fd5 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -493,7 +493,7 @@ SyncRepReleaseWaiters(void)
 	if (MyWalSnd->sync_standby_priority == 0 ||
 		(MyWalSnd->state != WALSNDSTATE_STREAMING &&
 		 MyWalSnd->state != WALSNDSTATE_STOPPING) ||
-		XLogRecPtrIsInvalid(MyWalSnd->flush))
+		!XLogRecPtrIsValid(MyWalSnd->flush))
 	{
 		announce_next_takeover = true;
 		return;
@@ -676,11 +676,11 @@ SyncRepGetOldestSyncRecPtr(XLogRecPtr *writePtr,
 		XLogRecPtr	flush = sync_standbys[i].flush;
 		XLogRecPtr	apply = sync_standbys[i].apply;
 
-		if (XLogRecPtrIsInvalid(*writePtr) || *writePtr > write)
+		if (!XLogRecPtrIsValid(*writePtr) || *writePtr > write)
 			*writePtr = write;
-		if (XLogRecPtrIsInvalid(*flushPtr) || *flushPtr > flush)
+		if (!XLogRecPtrIsValid(*flushPtr) || *flushPtr > flush)
 			*flushPtr = flush;
-		if (XLogRecPtrIsInvalid(*applyPtr) || *applyPtr > apply)
+		if (!XLogRecPtrIsValid(*applyPtr) || *applyPtr > apply)
 			*applyPtr = apply;
 	}
 }
@@ -799,7 +799,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 			continue;
 
 		/* Must have a valid flush position */
-		if (XLogRecPtrIsInvalid(stby->flush))
+		if (!XLogRecPtrIsValid(stby->flush))
 			continue;
 
 		/* OK, it's a candidate */
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index 7361ffc9dcf..2ee8fecee26 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1469,16 +1469,16 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	{
 		values[1] = CStringGetTextDatum(WalRcvGetStateString(state));
 
-		if (XLogRecPtrIsInvalid(receive_start_lsn))
+		if (!XLogRecPtrIsValid(receive_start_lsn))
 			nulls[2] = true;
 		else
 			values[2] = LSNGetDatum(receive_start_lsn);
 		values[3] = Int32GetDatum(receive_start_tli);
-		if (XLogRecPtrIsInvalid(written_lsn))
+		if (!XLogRecPtrIsValid(written_lsn))
 			nulls[4] = true;
 		else
 			values[4] = LSNGetDatum(written_lsn);
-		if (XLogRecPtrIsInvalid(flushed_lsn))
+		if (!XLogRecPtrIsValid(flushed_lsn))
 			nulls[5] = true;
 		else
 			values[5] = LSNGetDatum(flushed_lsn);
@@ -1491,7 +1491,7 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 			nulls[8] = true;
 		else
 			values[8] = TimestampTzGetDatum(last_receipt_time);
-		if (XLogRecPtrIsInvalid(latest_end_lsn))
+		if (!XLogRecPtrIsValid(latest_end_lsn))
 			nulls[9] = true;
 		else
 			values[9] = LSNGetDatum(latest_end_lsn);
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 548eafa7a73..b6dfb230d0d 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -529,7 +529,7 @@ ReadReplicationSlot(ReadReplicationSlotCmd *cmd)
 		i++;
 
 		/* start LSN */
-		if (!XLogRecPtrIsInvalid(slot_contents.data.restart_lsn))
+		if (XLogRecPtrIsValid(slot_contents.data.restart_lsn))
 		{
 			char		xloc[64];
 
@@ -541,7 +541,7 @@ ReadReplicationSlot(ReadReplicationSlotCmd *cmd)
 		i++;
 
 		/* timeline this WAL was produced on */
-		if (!XLogRecPtrIsInvalid(slot_contents.data.restart_lsn))
+		if (XLogRecPtrIsValid(slot_contents.data.restart_lsn))
 		{
 			TimeLineID	slots_position_timeline;
 			TimeLineID	current_timeline;
@@ -906,7 +906,7 @@ StartReplication(StartReplicationCmd *cmd)
 			 * that's older than the switchpoint, if it's still in the same
 			 * WAL segment.
 			 */
-			if (!XLogRecPtrIsInvalid(switchpoint) &&
+			if (XLogRecPtrIsValid(switchpoint) &&
 				switchpoint < cmd->startpoint)
 			{
 				ereport(ERROR,
@@ -1827,7 +1827,7 @@ WalSndWaitForWal(XLogRecPtr loc)
 	 * receipt of WAL up to RecentFlushPtr. This is particularly interesting
 	 * if we're far behind.
 	 */
-	if (!XLogRecPtrIsInvalid(RecentFlushPtr) &&
+	if (XLogRecPtrIsValid(RecentFlushPtr) &&
 		!NeedToWaitForWal(loc, RecentFlushPtr, &wait_event))
 		return RecentFlushPtr;
 
@@ -3597,7 +3597,7 @@ WalSndDone(WalSndSendDataCallback send_data)
 	 * flush location if valid, write otherwise. Tools like pg_receivewal will
 	 * usually (unless in synchronous mode) return an invalid flush location.
 	 */
-	replicatedPtr = XLogRecPtrIsInvalid(MyWalSnd->flush) ?
+	replicatedPtr = !XLogRecPtrIsValid(MyWalSnd->flush) ?
 		MyWalSnd->write : MyWalSnd->flush;
 
 	if (WalSndCaughtUp && sentPtr == replicatedPtr &&
@@ -4073,19 +4073,19 @@ pg_stat_get_wal_senders(PG_FUNCTION_ARGS)
 		{
 			values[1] = CStringGetTextDatum(WalSndGetStateString(state));
 
-			if (XLogRecPtrIsInvalid(sent_ptr))
+			if (!XLogRecPtrIsValid(sent_ptr))
 				nulls[2] = true;
 			values[2] = LSNGetDatum(sent_ptr);
 
-			if (XLogRecPtrIsInvalid(write))
+			if (!XLogRecPtrIsValid(write))
 				nulls[3] = true;
 			values[3] = LSNGetDatum(write);
 
-			if (XLogRecPtrIsInvalid(flush))
+			if (!XLogRecPtrIsValid(flush))
 				nulls[4] = true;
 			values[4] = LSNGetDatum(flush);
 
-			if (XLogRecPtrIsInvalid(apply))
+			if (!XLogRecPtrIsValid(apply))
 				nulls[5] = true;
 			values[5] = LSNGetDatum(apply);
 
@@ -4094,7 +4094,7 @@ pg_stat_get_wal_senders(PG_FUNCTION_ARGS)
 			 * which always returns an invalid flush location, as an
 			 * asynchronous standby.
 			 */
-			priority = XLogRecPtrIsInvalid(flush) ? 0 : priority;
+			priority = !XLogRecPtrIsValid(flush) ? 0 : priority;
 
 			if (writeLag < 0)
 				nulls[6] = true;
@@ -4165,7 +4165,7 @@ WalSndKeepalive(bool requestReply, XLogRecPtr writePtr)
 	/* construct the message... */
 	resetStringInfo(&output_message);
 	pq_sendbyte(&output_message, PqReplMsg_Keepalive);
-	pq_sendint64(&output_message, XLogRecPtrIsInvalid(writePtr) ? sentPtr : writePtr);
+	pq_sendint64(&output_message, !XLogRecPtrIsValid(writePtr) ? sentPtr : writePtr);
 	pq_sendint64(&output_message, GetCurrentTimestamp());
 	pq_sendbyte(&output_message, requestReply ? 1 : 0);
 
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index e8544acb784..1b5ef9ce10a 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -5545,7 +5545,7 @@ MarkBufferDirtyHint(Buffer buffer, bool buffer_std)
 			 * checksum here. That will happen when the page is written
 			 * sometime later in this checkpoint cycle.
 			 */
-			if (!XLogRecPtrIsInvalid(lsn))
+			if (XLogRecPtrIsValid(lsn))
 				PageSetLSN(page, lsn);
 		}
 
diff --git a/src/bin/pg_basebackup/pg_receivewal.c b/src/bin/pg_basebackup/pg_receivewal.c
index 289ca14dcfe..3e6f4a7fc48 100644
--- a/src/bin/pg_basebackup/pg_receivewal.c
+++ b/src/bin/pg_basebackup/pg_receivewal.c
@@ -192,7 +192,7 @@ stop_streaming(XLogRecPtr xlogpos, uint32 timeline, bool segment_finished)
 					LSN_FORMAT_ARGS(xlogpos),
 					timeline);
 
-	if (!XLogRecPtrIsInvalid(endpos) && endpos < xlogpos)
+	if (XLogRecPtrIsValid(endpos) && endpos < xlogpos)
 	{
 		if (verbose)
 			pg_log_info("stopped log streaming at %X/%08X (timeline %u)",
diff --git a/src/bin/pg_basebackup/pg_recvlogical.c b/src/bin/pg_basebackup/pg_recvlogical.c
index 7a4d1a2d2ca..6739784a993 100644
--- a/src/bin/pg_basebackup/pg_recvlogical.c
+++ b/src/bin/pg_basebackup/pg_recvlogical.c
@@ -1080,7 +1080,7 @@ prepareToTerminate(PGconn *conn, XLogRecPtr endpos, StreamStopReason reason,
 							LSN_FORMAT_ARGS(endpos));
 				break;
 			case STREAM_STOP_END_OF_WAL:
-				Assert(!XLogRecPtrIsInvalid(lsn));
+				Assert(XLogRecPtrIsValid(lsn));
 				pg_log_info("end position %X/%08X reached by WAL record at %X/%08X",
 							LSN_FORMAT_ARGS(endpos), LSN_FORMAT_ARGS(lsn));
 				break;
diff --git a/src/bin/pg_rewind/pg_rewind.c b/src/bin/pg_rewind/pg_rewind.c
index 1b953692b17..27c514f934a 100644
--- a/src/bin/pg_rewind/pg_rewind.c
+++ b/src/bin/pg_rewind/pg_rewind.c
@@ -850,9 +850,9 @@ progress_report(bool finished)
 static XLogRecPtr
 MinXLogRecPtr(XLogRecPtr a, XLogRecPtr b)
 {
-	if (XLogRecPtrIsInvalid(a))
+	if (!XLogRecPtrIsValid(a))
 		return b;
-	else if (XLogRecPtrIsInvalid(b))
+	else if (!XLogRecPtrIsValid(b))
 		return a;
 	else
 		return Min(a, b);
diff --git a/src/bin/pg_waldump/pg_waldump.c b/src/bin/pg_waldump/pg_waldump.c
index 13d3ec2f5be..19cf5461eac 100644
--- a/src/bin/pg_waldump/pg_waldump.c
+++ b/src/bin/pg_waldump/pg_waldump.c
@@ -637,7 +637,7 @@ XLogDumpDisplayStats(XLogDumpConfig *config, XLogStats *stats)
 	/*
 	 * Leave if no stats have been computed yet, as tracked by the end LSN.
 	 */
-	if (XLogRecPtrIsInvalid(stats->endptr))
+	if (!XLogRecPtrIsValid(stats->endptr))
 		return;
 
 	/*
@@ -1136,7 +1136,7 @@ main(int argc, char **argv)
 		/* parse position from file */
 		XLogFromFileName(fname, &private.timeline, &segno, WalSegSz);
 
-		if (XLogRecPtrIsInvalid(private.startptr))
+		if (!XLogRecPtrIsValid(private.startptr))
 			XLogSegNoOffsetToRecPtr(segno, 0, WalSegSz, private.startptr);
 		else if (!XLByteInSeg(private.startptr, segno, WalSegSz))
 		{
@@ -1147,7 +1147,7 @@ main(int argc, char **argv)
 		}
 
 		/* no second file specified, set end position */
-		if (!(optind + 1 < argc) && XLogRecPtrIsInvalid(private.endptr))
+		if (!(optind + 1 < argc) && !XLogRecPtrIsValid(private.endptr))
 			XLogSegNoOffsetToRecPtr(segno + 1, 0, WalSegSz, private.endptr);
 
 		/* parse ENDSEG if passed */
@@ -1170,7 +1170,7 @@ main(int argc, char **argv)
 				pg_fatal("ENDSEG %s is before STARTSEG %s",
 						 argv[optind + 1], argv[optind]);
 
-			if (XLogRecPtrIsInvalid(private.endptr))
+			if (!XLogRecPtrIsValid(private.endptr))
 				XLogSegNoOffsetToRecPtr(endsegno + 1, 0, WalSegSz,
 										private.endptr);
 
@@ -1192,7 +1192,7 @@ main(int argc, char **argv)
 		waldir = identify_target_directory(waldir, NULL);
 
 	/* we don't know what to print */
-	if (XLogRecPtrIsInvalid(private.startptr))
+	if (!XLogRecPtrIsValid(private.startptr))
 	{
 		pg_log_error("no start WAL location given");
 		goto bad_argument;
diff --git a/src/include/access/xlogdefs.h b/src/include/access/xlogdefs.h
index 2397fb24115..b16b2a1c8a3 100644
--- a/src/include/access/xlogdefs.h
+++ b/src/include/access/xlogdefs.h
@@ -26,8 +26,16 @@ typedef uint64 XLogRecPtr;
  * record can begin at zero.
  */
 #define InvalidXLogRecPtr	0
-#define XLogRecPtrIsInvalid(r)	((r) == InvalidXLogRecPtr)
+#define XLogRecPtrIsValid(r) ((r) != InvalidXLogRecPtr)
 
+/*
+ * New code should use XLogRecPtrIsValid() instead of XLogRecPtrIsInvalid()
+ * for consistency with the affirmative form of other *IsValid() macros and to
+ * avoid awkward double negative.
+ * This macro is retained for convenience of third-party code but could
+ * be deprecated in the future.
+ */
+#define XLogRecPtrIsInvalid(r)	((r) == InvalidXLogRecPtr)
 /*
  * First LSN to use for "fake" LSNs.
  *
-- 
2.34.1

v3-0002-Replace-InvalidXLogRecPtr-comparisons-with-XLogRe.patchtext/x-diff; charset=us-asciiDownload
From 2fab198c1752889db248084960a11fbc9968cdc9 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Wed, 29 Oct 2025 11:45:52 +0000
Subject: [PATCH v3 2/3] Replace InvalidXLogRecPtr comparisons with
 XLogRecPtrIsValid()

This commit ensures the XLogRecPtrIsValid() macro is used instead of direct
InvalidXLogRecPtr equality comparisons.
---
 src/backend/access/heap/rewriteheap.c         |  4 +-
 src/backend/access/heap/vacuumlazy.c          |  2 +-
 src/backend/access/transam/twophase.c         |  2 +-
 src/backend/access/transam/xlog.c             | 18 ++++-----
 src/backend/access/transam/xloginsert.c       |  4 +-
 src/backend/access/transam/xlogreader.c       |  2 +-
 src/backend/access/transam/xlogrecovery.c     |  8 ++--
 src/backend/access/transam/xlogutils.c        |  8 ++--
 src/backend/catalog/pg_subscription.c         |  4 +-
 src/backend/replication/logical/logical.c     | 30 +++++++--------
 .../replication/logical/logicalfuncs.c        |  4 +-
 src/backend/replication/logical/origin.c      | 18 ++++-----
 src/backend/replication/logical/proto.c       | 18 ++++-----
 .../replication/logical/reorderbuffer.c       | 38 +++++++++----------
 src/backend/replication/logical/snapbuild.c   | 14 +++----
 src/backend/replication/slot.c                | 18 ++++-----
 src/backend/replication/slotfuncs.c           |  6 +--
 src/backend/replication/walsender.c           |  6 +--
 src/bin/pg_basebackup/pg_receivewal.c         |  6 +--
 src/bin/pg_basebackup/pg_recvlogical.c        | 10 ++---
 src/bin/pg_waldump/pg_waldump.c               |  4 +-
 src/include/access/xlogdefs.h                 |  2 +-
 22 files changed, 113 insertions(+), 113 deletions(-)
  19.3% src/backend/access/transam/
  54.5% src/backend/replication/logical/
  12.3% src/backend/replication/
   3.6% src/backend/
   7.6% src/bin/pg_basebackup/

diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c
index 8061e92f044..66ab48f0fe0 100644
--- a/src/backend/access/heap/rewriteheap.c
+++ b/src/backend/access/heap/rewriteheap.c
@@ -1169,7 +1169,7 @@ CheckPointLogicalRewriteHeap(void)
 	cutoff = ReplicationSlotsComputeLogicalRestartLSN();
 
 	/* don't start earlier than the restart lsn */
-	if (cutoff != InvalidXLogRecPtr && redo < cutoff)
+	if (XLogRecPtrIsValid(cutoff) && redo < cutoff)
 		cutoff = redo;
 
 	mappings_dir = AllocateDir(PG_LOGICAL_MAPPINGS_DIR);
@@ -1204,7 +1204,7 @@ CheckPointLogicalRewriteHeap(void)
 
 		lsn = ((uint64) hi) << 32 | lo;
 
-		if (lsn < cutoff || cutoff == InvalidXLogRecPtr)
+		if (lsn < cutoff || !XLogRecPtrIsValid(cutoff))
 		{
 			elog(DEBUG1, "removing logical rewrite file \"%s\"", path);
 			if (unlink(path) < 0)
diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c
index d2b031fdd06..27fba1e3dd4 100644
--- a/src/backend/access/heap/vacuumlazy.c
+++ b/src/backend/access/heap/vacuumlazy.c
@@ -1900,7 +1900,7 @@ lazy_scan_new_or_empty(LVRelState *vacrel, Buffer buf, BlockNumber blkno,
 			 * WAL-logged, and if not, do that now.
 			 */
 			if (RelationNeedsWAL(vacrel->rel) &&
-				PageGetLSN(page) == InvalidXLogRecPtr)
+				!XLogRecPtrIsValid(PageGetLSN(page)))
 				log_newpage_buffer(buf, true);
 
 			PageSetAllVisible(page);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 8a92b292e56..89d0bfa7760 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -2198,7 +2198,7 @@ ProcessTwoPhaseBuffer(FullTransactionId fxid,
 	Assert(LWLockHeldByMeInMode(TwoPhaseStateLock, LW_EXCLUSIVE));
 
 	if (!fromdisk)
-		Assert(prepare_start_lsn != InvalidXLogRecPtr);
+		Assert(XLogRecPtrIsValid(prepare_start_lsn));
 
 	/* Already processed? */
 	if (TransactionIdDidCommit(XidFromFullTransactionId(fxid)) ||
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 4b827c17cfa..b2f53022805 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -848,7 +848,7 @@ XLogInsertRecord(XLogRecData *rdata,
 
 		if (doPageWrites &&
 			(!prevDoPageWrites ||
-			 (fpw_lsn != InvalidXLogRecPtr && fpw_lsn <= RedoRecPtr)))
+			 (XLogRecPtrIsValid(fpw_lsn) && fpw_lsn <= RedoRecPtr)))
 		{
 			/*
 			 * Oops, some buffer now needs to be backed up that the caller
@@ -882,7 +882,7 @@ XLogInsertRecord(XLogRecData *rdata,
 		 * Those checks are only needed for records that can contain buffer
 		 * references, and an XLOG_SWITCH record never does.
 		 */
-		Assert(fpw_lsn == InvalidXLogRecPtr);
+		Assert(!XLogRecPtrIsValid(fpw_lsn));
 		WALInsertLockAcquireExclusive();
 		inserted = ReserveXLogSwitch(&StartPos, &EndPos, &rechdr->xl_prev);
 	}
@@ -897,7 +897,7 @@ XLogInsertRecord(XLogRecData *rdata,
 		 * not check RedoRecPtr before inserting the record; we just need to
 		 * update it afterwards.
 		 */
-		Assert(fpw_lsn == InvalidXLogRecPtr);
+		Assert(!XLogRecPtrIsValid(fpw_lsn));
 		WALInsertLockAcquireExclusive();
 		ReserveXLogInsertLocation(rechdr->xl_tot_len, &StartPos, &EndPos,
 								  &rechdr->xl_prev);
@@ -1602,7 +1602,7 @@ WaitXLogInsertionsToFinish(XLogRecPtr upto)
 			 */
 		} while (insertingat < upto);
 
-		if (insertingat != InvalidXLogRecPtr && insertingat < finishedUpto)
+		if (XLogRecPtrIsValid(insertingat) && insertingat < finishedUpto)
 			finishedUpto = insertingat;
 	}
 
@@ -7356,7 +7356,7 @@ CreateCheckPoint(int flags)
 	 * Update the average distance between checkpoints if the prior checkpoint
 	 * exists.
 	 */
-	if (PriorRedoPtr != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(PriorRedoPtr))
 		UpdateCheckPointDistanceEstimate(RedoRecPtr - PriorRedoPtr);
 
 	INJECTION_POINT("checkpoint-before-old-wal-removal", NULL);
@@ -7804,7 +7804,7 @@ CreateRestartPoint(int flags)
 	 * Update the average distance between checkpoints/restartpoints if the
 	 * prior checkpoint exists.
 	 */
-	if (PriorRedoPtr != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(PriorRedoPtr))
 		UpdateCheckPointDistanceEstimate(RedoRecPtr - PriorRedoPtr);
 
 	/*
@@ -8011,7 +8011,7 @@ KeepLogSeg(XLogRecPtr recptr, XLogSegNo *logSegNo)
 
 	/* Calculate how many segments are kept by slots. */
 	keep = XLogGetReplicationSlotMinimumLSN();
-	if (keep != InvalidXLogRecPtr && keep < recptr)
+	if (XLogRecPtrIsValid(keep) && keep < recptr)
 	{
 		XLByteToSeg(keep, segno, wal_segment_size);
 
@@ -8038,7 +8038,7 @@ KeepLogSeg(XLogRecPtr recptr, XLogSegNo *logSegNo)
 	 * summarized.
 	 */
 	keep = GetOldestUnsummarizedLSN(NULL, NULL);
-	if (keep != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(keep))
 	{
 		XLogSegNo	unsummarized_segno;
 
@@ -8596,7 +8596,7 @@ xlog_redo(XLogReaderState *record)
 			LocalMinRecoveryPoint = ControlFile->minRecoveryPoint;
 			LocalMinRecoveryPointTLI = ControlFile->minRecoveryPointTLI;
 		}
-		if (LocalMinRecoveryPoint != InvalidXLogRecPtr && LocalMinRecoveryPoint < lsn)
+		if (XLogRecPtrIsValid(LocalMinRecoveryPoint) && LocalMinRecoveryPoint < lsn)
 		{
 			TimeLineID	replayTLI;
 
diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c
index 58cb4b1b00c..a56d5a55282 100644
--- a/src/backend/access/transam/xloginsert.c
+++ b/src/backend/access/transam/xloginsert.c
@@ -528,7 +528,7 @@ XLogInsert(RmgrId rmid, uint8 info)
 
 		EndPos = XLogInsertRecord(rdt, fpw_lsn, curinsert_flags, num_fpi,
 								  fpi_bytes, topxid_included);
-	} while (EndPos == InvalidXLogRecPtr);
+	} while (!XLogRecPtrIsValid(EndPos));
 
 	XLogResetInsertion();
 
@@ -639,7 +639,7 @@ XLogRecordAssemble(RmgrId rmid, uint8 info,
 			needs_backup = (page_lsn <= RedoRecPtr);
 			if (!needs_backup)
 			{
-				if (*fpw_lsn == InvalidXLogRecPtr || page_lsn < *fpw_lsn)
+				if (!XLogRecPtrIsValid(*fpw_lsn) || page_lsn < *fpw_lsn)
 					*fpw_lsn = page_lsn;
 			}
 		}
diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index aad16127e60..755f351143a 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -558,7 +558,7 @@ XLogDecodeNextRecord(XLogReaderState *state, bool nonblocking)
 
 	RecPtr = state->NextRecPtr;
 
-	if (state->DecodeRecPtr != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(state->DecodeRecPtr))
 	{
 		/* read the record after the one we just read */
 
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index 84df67b07d2..f1e90076576 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -757,9 +757,9 @@ InitWalRecovery(ControlFileData *ControlFile, bool *wasShutdown_ptr,
 		 * end-of-backup record), and we can enter archive recovery directly.
 		 */
 		if (ArchiveRecoveryRequested &&
-			(ControlFile->minRecoveryPoint != InvalidXLogRecPtr ||
+			(XLogRecPtrIsValid(ControlFile->minRecoveryPoint) ||
 			 ControlFile->backupEndRequired ||
-			 ControlFile->backupEndPoint != InvalidXLogRecPtr ||
+			 XLogRecPtrIsValid(ControlFile->backupEndPoint) ||
 			 ControlFile->state == DB_SHUTDOWNED))
 		{
 			InArchiveRecovery = true;
@@ -3151,7 +3151,7 @@ ReadRecord(XLogPrefetcher *xlogprefetcher, int emode,
 	/* Pass through parameters to XLogPageRead */
 	private->fetching_ckpt = fetching_ckpt;
 	private->emode = emode;
-	private->randAccess = (xlogreader->ReadRecPtr == InvalidXLogRecPtr);
+	private->randAccess = (!XLogRecPtrIsValid(xlogreader->ReadRecPtr));
 	private->replayTLI = replayTLI;
 
 	/* This is the first attempt to read this page. */
@@ -4336,7 +4336,7 @@ XLogFileReadAnyTLI(XLogSegNo segno, XLogSource source)
 		 * Skip scanning the timeline ID that the logfile segment to read
 		 * doesn't belong to
 		 */
-		if (hent->begin != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(hent->begin))
 		{
 			XLogSegNo	beginseg = 0;
 
diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c
index 38176d9688e..ce2a3e42146 100644
--- a/src/backend/access/transam/xlogutils.c
+++ b/src/backend/access/transam/xlogutils.c
@@ -710,7 +710,7 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage,
 	const XLogRecPtr lastReadPage = (state->seg.ws_segno *
 									 state->segcxt.ws_segsize + state->segoff);
 
-	Assert(wantPage != InvalidXLogRecPtr && wantPage % XLOG_BLCKSZ == 0);
+	Assert(XLogRecPtrIsValid(wantPage) && wantPage % XLOG_BLCKSZ == 0);
 	Assert(wantLength <= XLOG_BLCKSZ);
 	Assert(state->readLen == 0 || state->readLen <= XLOG_BLCKSZ);
 	Assert(currTLI != 0);
@@ -741,7 +741,7 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage,
 	 */
 	if (state->currTLI == currTLI && wantPage >= lastReadPage)
 	{
-		Assert(state->currTLIValidUntil == InvalidXLogRecPtr);
+		Assert(!XLogRecPtrIsValid(state->currTLIValidUntil));
 		return;
 	}
 
@@ -750,7 +750,7 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage,
 	 * timeline and the timeline we're reading from is valid until the end of
 	 * the current segment we can just keep reading.
 	 */
-	if (state->currTLIValidUntil != InvalidXLogRecPtr &&
+	if (XLogRecPtrIsValid(state->currTLIValidUntil) &&
 		state->currTLI != currTLI &&
 		state->currTLI != 0 &&
 		((wantPage + wantLength) / state->segcxt.ws_segsize) <
@@ -790,7 +790,7 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage,
 		state->currTLIValidUntil = tliSwitchPoint(state->currTLI, timelineHistory,
 												  &state->nextTLI);
 
-		Assert(state->currTLIValidUntil == InvalidXLogRecPtr ||
+		Assert(!XLogRecPtrIsValid(state->currTLIValidUntil) ||
 			   wantPage + wantLength < state->currTLIValidUntil);
 
 		list_free_deep(timelineHistory);
diff --git a/src/backend/catalog/pg_subscription.c b/src/backend/catalog/pg_subscription.c
index 15b233a37d8..d836ea80b4d 100644
--- a/src/backend/catalog/pg_subscription.c
+++ b/src/backend/catalog/pg_subscription.c
@@ -293,7 +293,7 @@ AddSubscriptionRelState(Oid subid, Oid relid, char state,
 	values[Anum_pg_subscription_rel_srsubid - 1] = ObjectIdGetDatum(subid);
 	values[Anum_pg_subscription_rel_srrelid - 1] = ObjectIdGetDatum(relid);
 	values[Anum_pg_subscription_rel_srsubstate - 1] = CharGetDatum(state);
-	if (sublsn != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(sublsn))
 		values[Anum_pg_subscription_rel_srsublsn - 1] = LSNGetDatum(sublsn);
 	else
 		nulls[Anum_pg_subscription_rel_srsublsn - 1] = true;
@@ -366,7 +366,7 @@ UpdateSubscriptionRelState(Oid subid, Oid relid, char state,
 	values[Anum_pg_subscription_rel_srsubstate - 1] = CharGetDatum(state);
 
 	replaces[Anum_pg_subscription_rel_srsublsn - 1] = true;
-	if (sublsn != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(sublsn))
 		values[Anum_pg_subscription_rel_srsublsn - 1] = LSNGetDatum(sublsn);
 	else
 		nulls[Anum_pg_subscription_rel_srsublsn - 1] = true;
diff --git a/src/backend/replication/logical/logical.c b/src/backend/replication/logical/logical.c
index 79717b52941..866f92cf799 100644
--- a/src/backend/replication/logical/logical.c
+++ b/src/backend/replication/logical/logical.c
@@ -546,9 +546,9 @@ CreateDecodingContext(XLogRecPtr start_lsn,
 
 	/* slot must be valid to allow decoding */
 	Assert(slot->data.invalidated == RS_INVAL_NONE);
-	Assert(slot->data.restart_lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(slot->data.restart_lsn));
 
-	if (start_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(start_lsn))
 	{
 		/* continue from last position */
 		start_lsn = slot->data.confirmed_flush;
@@ -757,7 +757,7 @@ output_plugin_error_callback(void *arg)
 	LogicalErrorCallbackState *state = (LogicalErrorCallbackState *) arg;
 
 	/* not all callbacks have an associated LSN  */
-	if (state->report_location != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(state->report_location))
 		errcontext("slot \"%s\", output plugin \"%s\", in the %s callback, associated LSN %X/%08X",
 				   NameStr(state->ctx->slot->data.name),
 				   NameStr(state->ctx->slot->data.plugin),
@@ -1711,7 +1711,7 @@ LogicalIncreaseXminForSlot(XLogRecPtr current_lsn, TransactionId xmin)
 	 * Only increase if the previous values have been applied, otherwise we
 	 * might never end up updating if the receiver acks too slowly.
 	 */
-	else if (slot->candidate_xmin_lsn == InvalidXLogRecPtr)
+	else if (!XLogRecPtrIsValid(slot->candidate_xmin_lsn))
 	{
 		slot->candidate_catalog_xmin = xmin;
 		slot->candidate_xmin_lsn = current_lsn;
@@ -1749,8 +1749,8 @@ LogicalIncreaseRestartDecodingForSlot(XLogRecPtr current_lsn, XLogRecPtr restart
 	slot = MyReplicationSlot;
 
 	Assert(slot != NULL);
-	Assert(restart_lsn != InvalidXLogRecPtr);
-	Assert(current_lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(restart_lsn));
+	Assert(XLogRecPtrIsValid(current_lsn));
 
 	SpinLockAcquire(&slot->mutex);
 
@@ -1779,7 +1779,7 @@ LogicalIncreaseRestartDecodingForSlot(XLogRecPtr current_lsn, XLogRecPtr restart
 	 * might never end up updating if the receiver acks too slowly. A missed
 	 * value here will just cause some extra effort after reconnecting.
 	 */
-	else if (slot->candidate_restart_valid == InvalidXLogRecPtr)
+	else if (!XLogRecPtrIsValid(slot->candidate_restart_valid))
 	{
 		slot->candidate_restart_valid = current_lsn;
 		slot->candidate_restart_lsn = restart_lsn;
@@ -1819,11 +1819,11 @@ LogicalIncreaseRestartDecodingForSlot(XLogRecPtr current_lsn, XLogRecPtr restart
 void
 LogicalConfirmReceivedLocation(XLogRecPtr lsn)
 {
-	Assert(lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(lsn));
 
 	/* Do an unlocked check for candidate_lsn first. */
-	if (MyReplicationSlot->candidate_xmin_lsn != InvalidXLogRecPtr ||
-		MyReplicationSlot->candidate_restart_valid != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(MyReplicationSlot->candidate_xmin_lsn) ||
+		XLogRecPtrIsValid(MyReplicationSlot->candidate_restart_valid))
 	{
 		bool		updated_xmin = false;
 		bool		updated_restart = false;
@@ -1849,7 +1849,7 @@ LogicalConfirmReceivedLocation(XLogRecPtr lsn)
 			MyReplicationSlot->data.confirmed_flush = lsn;
 
 		/* if we're past the location required for bumping xmin, do so */
-		if (MyReplicationSlot->candidate_xmin_lsn != InvalidXLogRecPtr &&
+		if (XLogRecPtrIsValid(MyReplicationSlot->candidate_xmin_lsn) &&
 			MyReplicationSlot->candidate_xmin_lsn <= lsn)
 		{
 			/*
@@ -1871,10 +1871,10 @@ LogicalConfirmReceivedLocation(XLogRecPtr lsn)
 			}
 		}
 
-		if (MyReplicationSlot->candidate_restart_valid != InvalidXLogRecPtr &&
+		if (XLogRecPtrIsValid(MyReplicationSlot->candidate_restart_valid) &&
 			MyReplicationSlot->candidate_restart_valid <= lsn)
 		{
-			Assert(MyReplicationSlot->candidate_restart_lsn != InvalidXLogRecPtr);
+			Assert(XLogRecPtrIsValid(MyReplicationSlot->candidate_restart_lsn));
 
 			MyReplicationSlot->data.restart_lsn = MyReplicationSlot->candidate_restart_lsn;
 			MyReplicationSlot->candidate_restart_lsn = InvalidXLogRecPtr;
@@ -2089,7 +2089,7 @@ LogicalSlotAdvanceAndCheckSnapState(XLogRecPtr moveto,
 	ResourceOwner old_resowner PG_USED_FOR_ASSERTS_ONLY = CurrentResourceOwner;
 	XLogRecPtr	retlsn;
 
-	Assert(moveto != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(moveto));
 
 	if (found_consistent_snapshot)
 		*found_consistent_snapshot = false;
@@ -2163,7 +2163,7 @@ LogicalSlotAdvanceAndCheckSnapState(XLogRecPtr moveto,
 		if (found_consistent_snapshot && DecodingContextReady(ctx))
 			*found_consistent_snapshot = true;
 
-		if (ctx->reader->EndRecPtr != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(ctx->reader->EndRecPtr))
 		{
 			LogicalConfirmReceivedLocation(moveto);
 
diff --git a/src/backend/replication/logical/logicalfuncs.c b/src/backend/replication/logical/logicalfuncs.c
index d78e486bca6..49b2aef3c74 100644
--- a/src/backend/replication/logical/logicalfuncs.c
+++ b/src/backend/replication/logical/logicalfuncs.c
@@ -276,7 +276,7 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin
 			}
 
 			/* check limits */
-			if (upto_lsn != InvalidXLogRecPtr &&
+			if (XLogRecPtrIsValid(upto_lsn) &&
 				upto_lsn <= ctx->reader->EndRecPtr)
 				break;
 			if (upto_nchanges != 0 &&
@@ -289,7 +289,7 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin
 		 * Next time, start where we left off. (Hunting things, the family
 		 * business..)
 		 */
-		if (ctx->reader->EndRecPtr != InvalidXLogRecPtr && confirm)
+		if (XLogRecPtrIsValid(ctx->reader->EndRecPtr) && confirm)
 		{
 			LogicalConfirmReceivedLocation(ctx->reader->EndRecPtr);
 
diff --git a/src/backend/replication/logical/origin.c b/src/backend/replication/logical/origin.c
index bcd5d9aad62..4632aa8115d 100644
--- a/src/backend/replication/logical/origin.c
+++ b/src/backend/replication/logical/origin.c
@@ -984,8 +984,8 @@ replorigin_advance(RepOriginId node,
 		/* initialize new slot */
 		LWLockAcquire(&free_state->lock, LW_EXCLUSIVE);
 		replication_state = free_state;
-		Assert(replication_state->remote_lsn == InvalidXLogRecPtr);
-		Assert(replication_state->local_lsn == InvalidXLogRecPtr);
+		Assert(!XLogRecPtrIsValid(replication_state->remote_lsn));
+		Assert(!XLogRecPtrIsValid(replication_state->local_lsn));
 		replication_state->roident = node;
 	}
 
@@ -1020,7 +1020,7 @@ replorigin_advance(RepOriginId node,
 	 */
 	if (go_backward || replication_state->remote_lsn < remote_commit)
 		replication_state->remote_lsn = remote_commit;
-	if (local_commit != InvalidXLogRecPtr &&
+	if (XLogRecPtrIsValid(local_commit) &&
 		(go_backward || replication_state->local_lsn < local_commit))
 		replication_state->local_lsn = local_commit;
 	LWLockRelease(&replication_state->lock);
@@ -1064,7 +1064,7 @@ replorigin_get_progress(RepOriginId node, bool flush)
 
 	LWLockRelease(ReplicationOriginLock);
 
-	if (flush && local_lsn != InvalidXLogRecPtr)
+	if (flush && XLogRecPtrIsValid(local_lsn))
 		XLogFlush(local_lsn);
 
 	return remote_lsn;
@@ -1197,8 +1197,8 @@ replorigin_session_setup(RepOriginId node, int acquired_by)
 
 		/* initialize new slot */
 		session_replication_state = &replication_states[free_slot];
-		Assert(session_replication_state->remote_lsn == InvalidXLogRecPtr);
-		Assert(session_replication_state->local_lsn == InvalidXLogRecPtr);
+		Assert(!XLogRecPtrIsValid(session_replication_state->remote_lsn));
+		Assert(!XLogRecPtrIsValid(session_replication_state->local_lsn));
 		session_replication_state->roident = node;
 	}
 
@@ -1282,7 +1282,7 @@ replorigin_session_get_progress(bool flush)
 	local_lsn = session_replication_state->local_lsn;
 	LWLockRelease(&session_replication_state->lock);
 
-	if (flush && local_lsn != InvalidXLogRecPtr)
+	if (flush && XLogRecPtrIsValid(local_lsn))
 		XLogFlush(local_lsn);
 
 	return remote_lsn;
@@ -1454,7 +1454,7 @@ pg_replication_origin_session_progress(PG_FUNCTION_ARGS)
 
 	remote_lsn = replorigin_session_get_progress(flush);
 
-	if (remote_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(remote_lsn))
 		PG_RETURN_NULL();
 
 	PG_RETURN_LSN(remote_lsn);
@@ -1543,7 +1543,7 @@ pg_replication_origin_progress(PG_FUNCTION_ARGS)
 
 	remote_lsn = replorigin_get_progress(roident, flush);
 
-	if (remote_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(remote_lsn))
 		PG_RETURN_NULL();
 
 	PG_RETURN_LSN(remote_lsn);
diff --git a/src/backend/replication/logical/proto.c b/src/backend/replication/logical/proto.c
index ed62888764c..f0a913892b9 100644
--- a/src/backend/replication/logical/proto.c
+++ b/src/backend/replication/logical/proto.c
@@ -64,7 +64,7 @@ logicalrep_read_begin(StringInfo in, LogicalRepBeginData *begin_data)
 {
 	/* read fields */
 	begin_data->final_lsn = pq_getmsgint64(in);
-	if (begin_data->final_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(begin_data->final_lsn))
 		elog(ERROR, "final_lsn not set in begin message");
 	begin_data->committime = pq_getmsgint64(in);
 	begin_data->xid = pq_getmsgint(in, 4);
@@ -135,10 +135,10 @@ logicalrep_read_begin_prepare(StringInfo in, LogicalRepPreparedTxnData *begin_da
 {
 	/* read fields */
 	begin_data->prepare_lsn = pq_getmsgint64(in);
-	if (begin_data->prepare_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(begin_data->prepare_lsn))
 		elog(ERROR, "prepare_lsn not set in begin prepare message");
 	begin_data->end_lsn = pq_getmsgint64(in);
-	if (begin_data->end_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(begin_data->end_lsn))
 		elog(ERROR, "end_lsn not set in begin prepare message");
 	begin_data->prepare_time = pq_getmsgint64(in);
 	begin_data->xid = pq_getmsgint(in, 4);
@@ -207,10 +207,10 @@ logicalrep_read_prepare_common(StringInfo in, char *msgtype,
 
 	/* read fields */
 	prepare_data->prepare_lsn = pq_getmsgint64(in);
-	if (prepare_data->prepare_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(prepare_data->prepare_lsn))
 		elog(ERROR, "prepare_lsn is not set in %s message", msgtype);
 	prepare_data->end_lsn = pq_getmsgint64(in);
-	if (prepare_data->end_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(prepare_data->end_lsn))
 		elog(ERROR, "end_lsn is not set in %s message", msgtype);
 	prepare_data->prepare_time = pq_getmsgint64(in);
 	prepare_data->xid = pq_getmsgint(in, 4);
@@ -274,10 +274,10 @@ logicalrep_read_commit_prepared(StringInfo in, LogicalRepCommitPreparedTxnData *
 
 	/* read fields */
 	prepare_data->commit_lsn = pq_getmsgint64(in);
-	if (prepare_data->commit_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(prepare_data->commit_lsn))
 		elog(ERROR, "commit_lsn is not set in commit prepared message");
 	prepare_data->end_lsn = pq_getmsgint64(in);
-	if (prepare_data->end_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(prepare_data->end_lsn))
 		elog(ERROR, "end_lsn is not set in commit prepared message");
 	prepare_data->commit_time = pq_getmsgint64(in);
 	prepare_data->xid = pq_getmsgint(in, 4);
@@ -333,10 +333,10 @@ logicalrep_read_rollback_prepared(StringInfo in,
 
 	/* read fields */
 	rollback_data->prepare_end_lsn = pq_getmsgint64(in);
-	if (rollback_data->prepare_end_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(rollback_data->prepare_end_lsn))
 		elog(ERROR, "prepare_end_lsn is not set in rollback prepared message");
 	rollback_data->rollback_end_lsn = pq_getmsgint64(in);
-	if (rollback_data->rollback_end_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(rollback_data->rollback_end_lsn))
 		elog(ERROR, "rollback_end_lsn is not set in rollback prepared message");
 	rollback_data->prepare_time = pq_getmsgint64(in);
 	rollback_data->rollback_time = pq_getmsgint64(in);
diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c
index b57aef9916d..eb6a84554b7 100644
--- a/src/backend/replication/logical/reorderbuffer.c
+++ b/src/backend/replication/logical/reorderbuffer.c
@@ -701,7 +701,7 @@ ReorderBufferTXNByXid(ReorderBuffer *rb, TransactionId xid, bool create,
 	{
 		/* initialize the new entry, if creation was requested */
 		Assert(ent != NULL);
-		Assert(lsn != InvalidXLogRecPtr);
+		Assert(XLogRecPtrIsValid(lsn));
 
 		ent->txn = ReorderBufferAllocTXN(rb);
 		ent->txn->xid = xid;
@@ -849,7 +849,7 @@ ReorderBufferQueueChange(ReorderBuffer *rb, TransactionId xid, XLogRecPtr lsn,
 	change->lsn = lsn;
 	change->txn = txn;
 
-	Assert(InvalidXLogRecPtr != lsn);
+	Assert(XLogRecPtrIsValid(lsn));
 	dlist_push_tail(&txn->changes, &change->node);
 	txn->nentries++;
 	txn->nentries_mem++;
@@ -966,14 +966,14 @@ AssertTXNLsnOrder(ReorderBuffer *rb)
 													iter.cur);
 
 		/* start LSN must be set */
-		Assert(cur_txn->first_lsn != InvalidXLogRecPtr);
+		Assert(XLogRecPtrIsValid(cur_txn->first_lsn));
 
 		/* If there is an end LSN, it must be higher than start LSN */
-		if (cur_txn->end_lsn != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(cur_txn->end_lsn))
 			Assert(cur_txn->first_lsn <= cur_txn->end_lsn);
 
 		/* Current initial LSN must be strictly higher than previous */
-		if (prev_first_lsn != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(prev_first_lsn))
 			Assert(prev_first_lsn < cur_txn->first_lsn);
 
 		/* known-as-subtxn txns must not be listed */
@@ -990,10 +990,10 @@ AssertTXNLsnOrder(ReorderBuffer *rb)
 
 		/* base snapshot (and its LSN) must be set */
 		Assert(cur_txn->base_snapshot != NULL);
-		Assert(cur_txn->base_snapshot_lsn != InvalidXLogRecPtr);
+		Assert(XLogRecPtrIsValid(cur_txn->base_snapshot_lsn));
 
 		/* current LSN must be strictly higher than previous */
-		if (prev_base_snap_lsn != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(prev_base_snap_lsn))
 			Assert(prev_base_snap_lsn < cur_txn->base_snapshot_lsn);
 
 		/* known-as-subtxn txns must not be listed */
@@ -1022,11 +1022,11 @@ AssertChangeLsnOrder(ReorderBufferTXN *txn)
 
 		cur_change = dlist_container(ReorderBufferChange, node, iter.cur);
 
-		Assert(txn->first_lsn != InvalidXLogRecPtr);
-		Assert(cur_change->lsn != InvalidXLogRecPtr);
+		Assert(XLogRecPtrIsValid(txn->first_lsn));
+		Assert(XLogRecPtrIsValid(cur_change->lsn));
 		Assert(txn->first_lsn <= cur_change->lsn);
 
-		if (txn->end_lsn != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(txn->end_lsn))
 			Assert(cur_change->lsn <= txn->end_lsn);
 
 		Assert(prev_lsn <= cur_change->lsn);
@@ -1053,7 +1053,7 @@ ReorderBufferGetOldestTXN(ReorderBuffer *rb)
 	txn = dlist_head_element(ReorderBufferTXN, node, &rb->toplevel_by_lsn);
 
 	Assert(!rbtxn_is_known_subxact(txn));
-	Assert(txn->first_lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(txn->first_lsn));
 	return txn;
 }
 
@@ -2276,7 +2276,7 @@ ReorderBufferProcessTXN(ReorderBuffer *rb, ReorderBufferTXN *txn,
 			 * We can't call start stream callback before processing first
 			 * change.
 			 */
-			if (prev_lsn == InvalidXLogRecPtr)
+			if (!XLogRecPtrIsValid(prev_lsn))
 			{
 				if (streaming)
 				{
@@ -2291,7 +2291,7 @@ ReorderBufferProcessTXN(ReorderBuffer *rb, ReorderBufferTXN *txn,
 			 * subtransactions. The changes may have the same LSN due to
 			 * MULTI_INSERT xlog records.
 			 */
-			Assert(prev_lsn == InvalidXLogRecPtr || prev_lsn <= change->lsn);
+			Assert(!XLogRecPtrIsValid(prev_lsn) || prev_lsn <= change->lsn);
 
 			prev_lsn = change->lsn;
 
@@ -2975,7 +2975,7 @@ ReorderBufferPrepare(ReorderBuffer *rb, TransactionId xid,
 	 * have been updated in it by now.
 	 */
 	Assert((txn->txn_flags & RBTXN_PREPARE_STATUS_MASK) == RBTXN_IS_PREPARED);
-	Assert(txn->final_lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(txn->final_lsn));
 
 	txn->gid = pstrdup(gid);
 
@@ -3041,7 +3041,7 @@ ReorderBufferFinishPrepared(ReorderBuffer *rb, TransactionId xid,
 		 */
 		Assert((txn->txn_flags & RBTXN_PREPARE_STATUS_MASK) ==
 			   (RBTXN_IS_PREPARED | RBTXN_SKIPPED_PREPARE));
-		Assert(txn->final_lsn != InvalidXLogRecPtr);
+		Assert(XLogRecPtrIsValid(txn->final_lsn));
 
 		/*
 		 * By this time the txn has the prepare record information and it is
@@ -4552,8 +4552,8 @@ ReorderBufferRestoreChanges(ReorderBuffer *rb, ReorderBufferTXN *txn,
 	dlist_mutable_iter cleanup_iter;
 	File	   *fd = &file->vfd;
 
-	Assert(txn->first_lsn != InvalidXLogRecPtr);
-	Assert(txn->final_lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(txn->first_lsn));
+	Assert(XLogRecPtrIsValid(txn->final_lsn));
 
 	/* free current entries, so we have memory for more */
 	dlist_foreach_modify(cleanup_iter, &txn->changes)
@@ -4860,8 +4860,8 @@ ReorderBufferRestoreCleanup(ReorderBuffer *rb, ReorderBufferTXN *txn)
 	XLogSegNo	cur;
 	XLogSegNo	last;
 
-	Assert(txn->first_lsn != InvalidXLogRecPtr);
-	Assert(txn->final_lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(txn->first_lsn));
+	Assert(XLogRecPtrIsValid(txn->final_lsn));
 
 	XLByteToSeg(txn->first_lsn, first, wal_segment_size);
 	XLByteToSeg(txn->final_lsn, last, wal_segment_size);
diff --git a/src/backend/replication/logical/snapbuild.c b/src/backend/replication/logical/snapbuild.c
index 98ddee20929..6e18baa33cb 100644
--- a/src/backend/replication/logical/snapbuild.c
+++ b/src/backend/replication/logical/snapbuild.c
@@ -1210,7 +1210,7 @@ SnapBuildProcessRunningXacts(SnapBuild *builder, XLogRecPtr lsn, xl_running_xact
 	 * oldest ongoing txn might have started when we didn't yet serialize
 	 * anything because we hadn't reached a consistent state yet.
 	 */
-	if (txn != NULL && txn->restart_decoding_lsn != InvalidXLogRecPtr)
+	if (txn != NULL && XLogRecPtrIsValid(txn->restart_decoding_lsn))
 		LogicalIncreaseRestartDecodingForSlot(lsn, txn->restart_decoding_lsn);
 
 	/*
@@ -1218,8 +1218,8 @@ SnapBuildProcessRunningXacts(SnapBuild *builder, XLogRecPtr lsn, xl_running_xact
 	 * we have one.
 	 */
 	else if (txn == NULL &&
-			 builder->reorder->current_restart_decoding_lsn != InvalidXLogRecPtr &&
-			 builder->last_serialized_snapshot != InvalidXLogRecPtr)
+			 XLogRecPtrIsValid(builder->reorder->current_restart_decoding_lsn) &&
+			 XLogRecPtrIsValid(builder->last_serialized_snapshot))
 		LogicalIncreaseRestartDecodingForSlot(lsn,
 											  builder->last_serialized_snapshot);
 }
@@ -1293,7 +1293,7 @@ SnapBuildFindSnapshot(SnapBuild *builder, XLogRecPtr lsn, xl_running_xacts *runn
 	 */
 	if (running->oldestRunningXid == running->nextXid)
 	{
-		if (builder->start_decoding_at == InvalidXLogRecPtr ||
+		if (!XLogRecPtrIsValid(builder->start_decoding_at) ||
 			builder->start_decoding_at <= lsn)
 			/* can decode everything after this */
 			builder->start_decoding_at = lsn + 1;
@@ -1509,8 +1509,8 @@ SnapBuildSerialize(SnapBuild *builder, XLogRecPtr lsn)
 	struct stat stat_buf;
 	Size		sz;
 
-	Assert(lsn != InvalidXLogRecPtr);
-	Assert(builder->last_serialized_snapshot == InvalidXLogRecPtr ||
+	Assert(XLogRecPtrIsValid(lsn));
+	Assert(!XLogRecPtrIsValid(builder->last_serialized_snapshot) ||
 		   builder->last_serialized_snapshot <= lsn);
 
 	/*
@@ -2029,7 +2029,7 @@ CheckPointSnapBuild(void)
 		lsn = ((uint64) hi) << 32 | lo;
 
 		/* check whether we still need it */
-		if (lsn < cutoff || cutoff == InvalidXLogRecPtr)
+		if (lsn < cutoff || !XLogRecPtrIsValid(cutoff))
 		{
 			elog(DEBUG1, "removing snapbuild snapshot %s", path);
 
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index 0cb93dc90f2..1ec1e997b27 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -1270,15 +1270,15 @@ ReplicationSlotsComputeRequiredLSN(void)
 		 */
 		if (persistency == RS_PERSISTENT)
 		{
-			if (last_saved_restart_lsn != InvalidXLogRecPtr &&
+			if (XLogRecPtrIsValid(last_saved_restart_lsn) &&
 				restart_lsn > last_saved_restart_lsn)
 			{
 				restart_lsn = last_saved_restart_lsn;
 			}
 		}
 
-		if (restart_lsn != InvalidXLogRecPtr &&
-			(min_required == InvalidXLogRecPtr ||
+		if (XLogRecPtrIsValid(restart_lsn) &&
+			(!XLogRecPtrIsValid(min_required) ||
 			 restart_lsn < min_required))
 			min_required = restart_lsn;
 	}
@@ -1350,17 +1350,17 @@ ReplicationSlotsComputeLogicalRestartLSN(void)
 		 */
 		if (persistency == RS_PERSISTENT)
 		{
-			if (last_saved_restart_lsn != InvalidXLogRecPtr &&
+			if (XLogRecPtrIsValid(last_saved_restart_lsn) &&
 				restart_lsn > last_saved_restart_lsn)
 			{
 				restart_lsn = last_saved_restart_lsn;
 			}
 		}
 
-		if (restart_lsn == InvalidXLogRecPtr)
+		if (!XLogRecPtrIsValid(restart_lsn))
 			continue;
 
-		if (result == InvalidXLogRecPtr ||
+		if (!XLogRecPtrIsValid(result) ||
 			restart_lsn < result)
 			result = restart_lsn;
 	}
@@ -1573,8 +1573,8 @@ ReplicationSlotReserveWal(void)
 	ReplicationSlot *slot = MyReplicationSlot;
 
 	Assert(slot != NULL);
-	Assert(slot->data.restart_lsn == InvalidXLogRecPtr);
-	Assert(slot->last_saved_restart_lsn == InvalidXLogRecPtr);
+	Assert(!XLogRecPtrIsValid(slot->data.restart_lsn));
+	Assert(!XLogRecPtrIsValid(slot->last_saved_restart_lsn));
 
 	/*
 	 * The replication slot mechanism is used to prevent removal of required
@@ -1754,7 +1754,7 @@ DetermineSlotInvalidationCause(uint32 possible_causes, ReplicationSlot *s,
 	{
 		XLogRecPtr	restart_lsn = s->data.restart_lsn;
 
-		if (restart_lsn != InvalidXLogRecPtr &&
+		if (XLogRecPtrIsValid(restart_lsn) &&
 			restart_lsn < oldestLSN)
 			return RS_INVAL_WAL_REMOVED;
 	}
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 5aecd5c6a50..0478fc9c977 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -308,12 +308,12 @@ pg_get_replication_slots(PG_FUNCTION_ARGS)
 		else
 			nulls[i++] = true;
 
-		if (slot_contents.data.restart_lsn != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(slot_contents.data.restart_lsn))
 			values[i++] = LSNGetDatum(slot_contents.data.restart_lsn);
 		else
 			nulls[i++] = true;
 
-		if (slot_contents.data.confirmed_flush != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(slot_contents.data.confirmed_flush))
 			values[i++] = LSNGetDatum(slot_contents.data.confirmed_flush);
 		else
 			nulls[i++] = true;
@@ -467,7 +467,7 @@ pg_physical_replication_slot_advance(XLogRecPtr moveto)
 	XLogRecPtr	startlsn = MyReplicationSlot->data.restart_lsn;
 	XLogRecPtr	retlsn = startlsn;
 
-	Assert(moveto != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(moveto));
 
 	if (startlsn < moveto)
 	{
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index b6dfb230d0d..4a678e60b74 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -2397,7 +2397,7 @@ PhysicalConfirmReceivedLocation(XLogRecPtr lsn)
 	bool		changed = false;
 	ReplicationSlot *slot = MyReplicationSlot;
 
-	Assert(lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(lsn));
 	SpinLockAcquire(&slot->mutex);
 	if (slot->data.restart_lsn != lsn)
 	{
@@ -2519,7 +2519,7 @@ ProcessStandbyReplyMessage(void)
 	/*
 	 * Advance our local xmin horizon when the client confirmed a flush.
 	 */
-	if (MyReplicationSlot && flushPtr != InvalidXLogRecPtr)
+	if (MyReplicationSlot && XLogRecPtrIsValid(flushPtr))
 	{
 		if (SlotIsLogical(MyReplicationSlot))
 			LogicalConfirmReceivedLocation(flushPtr);
@@ -3536,7 +3536,7 @@ XLogSendLogical(void)
 	 * If first time through in this session, initialize flushPtr.  Otherwise,
 	 * we only need to update flushPtr if EndRecPtr is past it.
 	 */
-	if (flushPtr == InvalidXLogRecPtr ||
+	if (!XLogRecPtrIsValid(flushPtr) ||
 		logical_decoding_ctx->reader->EndRecPtr >= flushPtr)
 	{
 		/*
diff --git a/src/bin/pg_basebackup/pg_receivewal.c b/src/bin/pg_basebackup/pg_receivewal.c
index 3e6f4a7fc48..46e553dce4b 100644
--- a/src/bin/pg_basebackup/pg_receivewal.c
+++ b/src/bin/pg_basebackup/pg_receivewal.c
@@ -535,7 +535,7 @@ StreamLog(void)
 	 * Figure out where to start streaming.  First scan the local directory.
 	 */
 	stream.startpos = FindStreamingStart(&stream.timeline);
-	if (stream.startpos == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(stream.startpos))
 	{
 		/*
 		 * Try to get the starting point from the slot if any.  This is
@@ -556,14 +556,14 @@ StreamLog(void)
 		 * If it the starting point is still not known, use the current WAL
 		 * flush value as last resort.
 		 */
-		if (stream.startpos == InvalidXLogRecPtr)
+		if (!XLogRecPtrIsValid(stream.startpos))
 		{
 			stream.startpos = serverpos;
 			stream.timeline = servertli;
 		}
 	}
 
-	Assert(stream.startpos != InvalidXLogRecPtr &&
+	Assert(XLogRecPtrIsValid(stream.startpos) &&
 		   stream.timeline != 0);
 
 	/*
diff --git a/src/bin/pg_basebackup/pg_recvlogical.c b/src/bin/pg_basebackup/pg_recvlogical.c
index 6739784a993..14ad1504678 100644
--- a/src/bin/pg_basebackup/pg_recvlogical.c
+++ b/src/bin/pg_basebackup/pg_recvlogical.c
@@ -482,7 +482,7 @@ StreamLogicalLog(void)
 			}
 			replyRequested = copybuf[pos];
 
-			if (endpos != InvalidXLogRecPtr && walEnd >= endpos)
+			if (XLogRecPtrIsValid(endpos) && walEnd >= endpos)
 			{
 				/*
 				 * If there's nothing to read on the socket until a keepalive
@@ -535,7 +535,7 @@ StreamLogicalLog(void)
 		/* Extract WAL location for this block */
 		cur_record_lsn = fe_recvint64(&copybuf[1]);
 
-		if (endpos != InvalidXLogRecPtr && cur_record_lsn > endpos)
+		if (XLogRecPtrIsValid(endpos) && cur_record_lsn > endpos)
 		{
 			/*
 			 * We've read past our endpoint, so prepare to go away being
@@ -583,7 +583,7 @@ StreamLogicalLog(void)
 			goto error;
 		}
 
-		if (endpos != InvalidXLogRecPtr && cur_record_lsn == endpos)
+		if (XLogRecPtrIsValid(endpos) && cur_record_lsn == endpos)
 		{
 			/* endpos was exactly the record we just processed, we're done */
 			if (!flushAndSendFeedback(conn, &now))
@@ -913,14 +913,14 @@ main(int argc, char **argv)
 		exit(1);
 	}
 
-	if (startpos != InvalidXLogRecPtr && (do_create_slot || do_drop_slot))
+	if (XLogRecPtrIsValid(startpos) && (do_create_slot || do_drop_slot))
 	{
 		pg_log_error("cannot use --create-slot or --drop-slot together with --startpos");
 		pg_log_error_hint("Try \"%s --help\" for more information.", progname);
 		exit(1);
 	}
 
-	if (endpos != InvalidXLogRecPtr && !do_start_slot)
+	if (XLogRecPtrIsValid(endpos) && !do_start_slot)
 	{
 		pg_log_error("--endpos may only be specified with --start");
 		pg_log_error_hint("Try \"%s --help\" for more information.", progname);
diff --git a/src/bin/pg_waldump/pg_waldump.c b/src/bin/pg_waldump/pg_waldump.c
index 19cf5461eac..c6d6ba79e44 100644
--- a/src/bin/pg_waldump/pg_waldump.c
+++ b/src/bin/pg_waldump/pg_waldump.c
@@ -393,7 +393,7 @@ WALDumpReadPage(XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen,
 	int			count = XLOG_BLCKSZ;
 	WALReadError errinfo;
 
-	if (private->endptr != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(private->endptr))
 	{
 		if (targetPagePtr + XLOG_BLCKSZ <= private->endptr)
 			count = XLOG_BLCKSZ;
@@ -1213,7 +1213,7 @@ main(int argc, char **argv)
 	/* first find a valid recptr to start from */
 	first_record = XLogFindNextRecord(xlogreader_state, private.startptr);
 
-	if (first_record == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(first_record))
 		pg_fatal("could not find a valid record after %X/%08X",
 				 LSN_FORMAT_ARGS(private.startptr));
 
diff --git a/src/include/access/xlogdefs.h b/src/include/access/xlogdefs.h
index b16b2a1c8a3..4c419b256d3 100644
--- a/src/include/access/xlogdefs.h
+++ b/src/include/access/xlogdefs.h
@@ -35,7 +35,7 @@ typedef uint64 XLogRecPtr;
  * This macro is retained for convenience of third-party code but could
  * be deprecated in the future.
  */
-#define XLogRecPtrIsInvalid(r)	((r) == InvalidXLogRecPtr)
+#define XLogRecPtrIsInvalid(r)	(!XLogRecPtrIsValid((r)))
 /*
  * First LSN to use for "fake" LSNs.
  *
-- 
2.34.1

v3-0003-Replace-literal-0-comparisons-on-XLogRecPtr-with-.patchtext/x-diff; charset=us-asciiDownload
From 908b6c8db54f8b9ea667770c7537d60d64b40547 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Wed, 29 Oct 2025 18:46:28 +0000
Subject: [PATCH v3 3/3] Replace literal 0 comparisons on XLogRecPtr with
 XLogRecPtrIsValid()

This commit ensures the XLogRecPtrIsValid() macro is used instead of direct
literal 0 comparisons on XLogRecPtr.
---
 src/backend/access/transam/xlogfuncs.c     | 4 ++--
 src/backend/replication/walreceiverfuncs.c | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)
  42.3% src/backend/access/transam/
  57.6% src/backend/replication/

diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index 8c3090165f0..3e45fce43ed 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -341,7 +341,7 @@ pg_last_wal_receive_lsn(PG_FUNCTION_ARGS)
 
 	recptr = GetWalRcvFlushRecPtr(NULL, NULL);
 
-	if (recptr == 0)
+	if (!XLogRecPtrIsValid(recptr))
 		PG_RETURN_NULL();
 
 	PG_RETURN_LSN(recptr);
@@ -360,7 +360,7 @@ pg_last_wal_replay_lsn(PG_FUNCTION_ARGS)
 
 	recptr = GetXLogReplayRecPtr(NULL);
 
-	if (recptr == 0)
+	if (!XLogRecPtrIsValid(recptr))
 		PG_RETURN_NULL();
 
 	PG_RETURN_LSN(recptr);
diff --git a/src/backend/replication/walreceiverfuncs.c b/src/backend/replication/walreceiverfuncs.c
index 8de2886ff0b..f447ded2d07 100644
--- a/src/backend/replication/walreceiverfuncs.c
+++ b/src/backend/replication/walreceiverfuncs.c
@@ -301,7 +301,7 @@ RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, const char *conninfo,
 	 * If this is the first startup of walreceiver (on this timeline),
 	 * initialize flushedUpto and latestChunkStart to the starting point.
 	 */
-	if (walrcv->receiveStart == 0 || walrcv->receivedTLI != tli)
+	if (!XLogRecPtrIsValid(walrcv->receiveStart) || walrcv->receivedTLI != tli)
 	{
 		walrcv->flushedUpto = recptr;
 		walrcv->receivedTLI = tli;
-- 
2.34.1

#15Álvaro Herrera
alvherre@kurilemu.de
In reply to: Bertrand Drouvot (#12)
Re: Consistently use the XLogRecPtrIsInvalid() macro

On 2025-Oct-31, Bertrand Drouvot wrote:

After giving it more thought, I'm inclined to postpone the compiler warning
until XLogRecPtrIsValid() has been available for some time. The question is for
how long?

Maybe we can mark it so that it becomes obsolete in a future version,

#if PG_VERSION_NUM >= 210000
[[obsolete]]
#endif
XLogRecPtrIsInvalid( .. )

so that people using it today won't get any noise, but once they do get
the warning, the versions without the other macro are already out of
support, so they can switch to the new one easily. (This presupposes
that we'd add the new macro to older branches as well, which shouldn't
be a problem.) Only extensions wishing to support PG versions older
than we support would have to work slightly harder, but that should be OK.

--
Álvaro Herrera Breisgau, Deutschland — https://www.EnterpriseDB.com/
"I dream about dreams about dreams", sang the nightingale
under the pale moon (Sandman)

#16Bertrand Drouvot
bertranddrouvot.pg@gmail.com
In reply to: Álvaro Herrera (#15)
4 attachment(s)
Re: Consistently use the XLogRecPtrIsInvalid() macro

Hi,

On Fri, Oct 31, 2025 at 01:19:50PM +0100, �lvaro Herrera wrote:

On 2025-Oct-31, Bertrand Drouvot wrote:

After giving it more thought, I'm inclined to postpone the compiler warning
until XLogRecPtrIsValid() has been available for some time. The question is for
how long?

Maybe we can mark it so that it becomes obsolete in a future version,

#if PG_VERSION_NUM >= 210000
[[obsolete]]
#endif
XLogRecPtrIsInvalid( .. )

so that people using it today won't get any noise, but once they do get
the warning, the versions without the other macro are already out of
support, so they can switch to the new one easily. (This presupposes
that we'd add the new macro to older branches as well, which shouldn't
be a problem.) Only extensions wishing to support PG versions older
than we support would have to work slightly harder, but that should be OK.

Yeah, I did not think of checking PG_VERSION_NUM for a "future" version, that's
a good idea! I did it that way in the attached (in 0002) and introduced
PG_DEPRECATED() (as suggested by Peter upthread).

The version check is done on 24 to ensure that the new macro is available on all
the supported major versions.

The PG_DEPRECATED() name and location (c.h) look fine to me but maybe there is
better suggestions.

I think the way it is done in the attached makes sense, it:

- introduces PG_DEPRECATED()
- provides a use case on how to use it (i.e using a version that is currently
in the future)
- ensures that XLogRecPtrIsInvalid() deprecation is "enforced" as of version 24
- ensures that not using XLogRecPtrIsInvalid() is documented (so that it should
not be used anymore, at least in core, even waiting for version 24)

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

Attachments:

v4-0001-Introduce-XLogRecPtrIsValid-and-replace-XLogRecPt.patchtext/x-diff; charset=us-asciiDownload
From 61651a5be8035470e0f6d038c231f37f8b873df8 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Wed, 29 Oct 2025 10:34:03 +0000
Subject: [PATCH v4 1/4] Introduce XLogRecPtrIsValid() and replace
 XLogRecPtrIsInvalid() calls

XLogRecPtrIsInvalid() is inconsistent with the affirmative form of other
*IsValid() macros and leads to awkward double negative.

This commit introduces XLogRecPtrIsValid() and replace all the
XLogRecPtrIsInvalid() calls.

It also adds a comment mentioning that new code should use XLogRecPtrIsValid()
instead of XLogRecPtrIsInvalid() and that XLogRecPtrIsInvalid() could be
deprecated in the future.
---
 contrib/pg_walinspect/pg_walinspect.c         |  4 +--
 src/backend/access/gist/gist.c                |  4 +--
 src/backend/access/gist/gistget.c             |  4 +--
 src/backend/access/gist/gistutil.c            |  2 +-
 src/backend/access/heap/visibilitymap.c       |  4 +--
 src/backend/access/transam/clog.c             |  5 ++--
 src/backend/access/transam/slru.c             |  2 +-
 src/backend/access/transam/timeline.c         |  4 +--
 src/backend/access/transam/twophase.c         |  4 +--
 src/backend/access/transam/xlog.c             | 30 +++++++++----------
 src/backend/access/transam/xlogbackup.c       |  4 +--
 src/backend/access/transam/xlogreader.c       |  6 ++--
 src/backend/access/transam/xlogrecovery.c     | 12 ++++----
 src/backend/backup/backup_manifest.c          |  4 +--
 src/backend/backup/basebackup_incremental.c   |  2 +-
 src/backend/backup/walsummary.c               |  8 ++---
 src/backend/commands/subscriptioncmds.c       |  6 ++--
 src/backend/postmaster/walsummarizer.c        | 18 +++++------
 .../replication/logical/applyparallelworker.c |  4 +--
 src/backend/replication/logical/launcher.c    |  4 +--
 src/backend/replication/logical/logical.c     |  2 +-
 .../replication/logical/logicalfuncs.c        |  2 +-
 src/backend/replication/logical/slotsync.c    |  6 ++--
 src/backend/replication/logical/worker.c      | 16 +++++-----
 src/backend/replication/slot.c                | 10 +++----
 src/backend/replication/slotfuncs.c           | 16 +++++-----
 src/backend/replication/syncrep.c             | 10 +++----
 src/backend/replication/walreceiver.c         |  8 ++---
 src/backend/replication/walsender.c           | 22 +++++++-------
 src/backend/storage/buffer/bufmgr.c           |  2 +-
 src/bin/pg_basebackup/pg_receivewal.c         |  2 +-
 src/bin/pg_basebackup/pg_recvlogical.c        |  2 +-
 src/bin/pg_rewind/pg_rewind.c                 |  4 +--
 src/bin/pg_waldump/pg_waldump.c               | 10 +++----
 src/include/access/xlogdefs.h                 | 10 ++++++-
 35 files changed, 131 insertions(+), 122 deletions(-)
   4.2% src/backend/access/gist/
  26.7% src/backend/access/transam/
   6.4% src/backend/backup/
   7.6% src/backend/postmaster/
  14.0% src/backend/replication/logical/
  26.2% src/backend/replication/
   4.1% src/backend/
   3.7% src/bin/pg_waldump/
   5.2% src/

diff --git a/contrib/pg_walinspect/pg_walinspect.c b/contrib/pg_walinspect/pg_walinspect.c
index 501cea8fc1a..3c5e4a856a7 100644
--- a/contrib/pg_walinspect/pg_walinspect.c
+++ b/contrib/pg_walinspect/pg_walinspect.c
@@ -83,7 +83,7 @@ GetCurrentLSN(void)
 	else
 		curr_lsn = GetXLogReplayRecPtr(NULL);
 
-	Assert(!XLogRecPtrIsInvalid(curr_lsn));
+	Assert(XLogRecPtrIsValid(curr_lsn));
 
 	return curr_lsn;
 }
@@ -127,7 +127,7 @@ InitXLogReaderState(XLogRecPtr lsn)
 	/* first find a valid recptr to start from */
 	first_valid_record = XLogFindNextRecord(xlogreader, lsn);
 
-	if (XLogRecPtrIsInvalid(first_valid_record))
+	if (!XLogRecPtrIsValid(first_valid_record))
 		ereport(ERROR,
 				errmsg("could not find a valid record after %X/%08X",
 					   LSN_FORMAT_ARGS(lsn)));
diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c
index 5213cd71e97..3fb1a1285c5 100644
--- a/src/backend/access/gist/gist.c
+++ b/src/backend/access/gist/gist.c
@@ -682,7 +682,7 @@ gistdoinsert(Relation r, IndexTuple itup, Size freespace,
 			state.stack = stack = stack->parent;
 		}
 
-		if (XLogRecPtrIsInvalid(stack->lsn))
+		if (!XLogRecPtrIsValid(stack->lsn))
 			stack->buffer = ReadBuffer(state.r, stack->blkno);
 
 		/*
@@ -698,7 +698,7 @@ gistdoinsert(Relation r, IndexTuple itup, Size freespace,
 		stack->page = BufferGetPage(stack->buffer);
 		stack->lsn = xlocked ?
 			PageGetLSN(stack->page) : BufferGetLSNAtomic(stack->buffer);
-		Assert(!RelationNeedsWAL(state.r) || !XLogRecPtrIsInvalid(stack->lsn));
+		Assert(!RelationNeedsWAL(state.r) || XLogRecPtrIsValid(stack->lsn));
 
 		/*
 		 * If this page was split but the downlink was never inserted to the
diff --git a/src/backend/access/gist/gistget.c b/src/backend/access/gist/gistget.c
index 387d9972345..9ba45acfff3 100644
--- a/src/backend/access/gist/gistget.c
+++ b/src/backend/access/gist/gistget.c
@@ -46,7 +46,7 @@ gistkillitems(IndexScanDesc scan)
 	bool		killedsomething = false;
 
 	Assert(so->curBlkno != InvalidBlockNumber);
-	Assert(!XLogRecPtrIsInvalid(so->curPageLSN));
+	Assert(XLogRecPtrIsValid(so->curPageLSN));
 	Assert(so->killedItems != NULL);
 
 	buffer = ReadBuffer(scan->indexRelation, so->curBlkno);
@@ -353,7 +353,7 @@ gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem,
 	 * parentlsn < nsn), or if the system crashed after a page split but
 	 * before the downlink was inserted into the parent.
 	 */
-	if (!XLogRecPtrIsInvalid(pageItem->data.parentlsn) &&
+	if (XLogRecPtrIsValid(pageItem->data.parentlsn) &&
 		(GistFollowRight(page) ||
 		 pageItem->data.parentlsn < GistPageGetNSN(page)) &&
 		opaque->rightlink != InvalidBlockNumber /* sanity check */ )
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index 98b79608341..75272827837 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -1040,7 +1040,7 @@ gistGetFakeLSN(Relation rel)
 		Assert(!RelationNeedsWAL(rel));
 
 		/* No need for an actual record if we already have a distinct LSN */
-		if (!XLogRecPtrIsInvalid(lastlsn) && lastlsn == currlsn)
+		if (XLogRecPtrIsValid(lastlsn) && lastlsn == currlsn)
 			currlsn = gistXLogAssignLSN();
 
 		lastlsn = currlsn;
diff --git a/src/backend/access/heap/visibilitymap.c b/src/backend/access/heap/visibilitymap.c
index 2f5e61e2392..d14588e92ae 100644
--- a/src/backend/access/heap/visibilitymap.c
+++ b/src/backend/access/heap/visibilitymap.c
@@ -260,7 +260,7 @@ visibilitymap_set(Relation rel, BlockNumber heapBlk, Buffer heapBuf,
 		 flags, RelationGetRelationName(rel), heapBlk);
 #endif
 
-	Assert(InRecovery || XLogRecPtrIsInvalid(recptr));
+	Assert(InRecovery || !XLogRecPtrIsValid(recptr));
 	Assert(InRecovery || PageIsAllVisible(BufferGetPage(heapBuf)));
 	Assert((flags & VISIBILITYMAP_VALID_BITS) == flags);
 
@@ -292,7 +292,7 @@ visibilitymap_set(Relation rel, BlockNumber heapBlk, Buffer heapBuf,
 
 		if (RelationNeedsWAL(rel))
 		{
-			if (XLogRecPtrIsInvalid(recptr))
+			if (!XLogRecPtrIsValid(recptr))
 			{
 				Assert(!InRecovery);
 				recptr = log_heap_visible(rel, heapBuf, vmBuf, cutoff_xid, flags);
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index e80fbe109cf..ea43b432daf 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -381,7 +381,8 @@ TransactionIdSetPageStatusInternal(TransactionId xid, int nsubxids,
 	 * write-busy, since we don't care if the update reaches disk sooner than
 	 * we think.
 	 */
-	slotno = SimpleLruReadPage(XactCtl, pageno, XLogRecPtrIsInvalid(lsn), xid);
+	slotno = SimpleLruReadPage(XactCtl, pageno, !XLogRecPtrIsValid(lsn),
+							   xid);
 
 	/*
 	 * Set the main transaction id, if any.
@@ -705,7 +706,7 @@ TransactionIdSetStatusBit(TransactionId xid, XidStatus status, XLogRecPtr lsn, i
 	 * recovery. After recovery completes the next clog change will set the
 	 * LSN correctly.
 	 */
-	if (!XLogRecPtrIsInvalid(lsn))
+	if (XLogRecPtrIsValid(lsn))
 	{
 		int			lsnindex = GetLSNIndex(slotno, xid);
 
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index 5d3fcd62c94..77676d6d035 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -937,7 +937,7 @@ SlruPhysicalWritePage(SlruCtl ctl, int64 pageno, int slotno, SlruWriteAll fdata)
 				max_lsn = this_lsn;
 		}
 
-		if (!XLogRecPtrIsInvalid(max_lsn))
+		if (XLogRecPtrIsValid(max_lsn))
 		{
 			/*
 			 * As noted above, elog(ERROR) is not acceptable here, so if
diff --git a/src/backend/access/transam/timeline.c b/src/backend/access/transam/timeline.c
index 186eb91f609..ec3e323ec0c 100644
--- a/src/backend/access/transam/timeline.c
+++ b/src/backend/access/transam/timeline.c
@@ -549,8 +549,8 @@ tliOfPointInHistory(XLogRecPtr ptr, List *history)
 	{
 		TimeLineHistoryEntry *tle = (TimeLineHistoryEntry *) lfirst(cell);
 
-		if ((XLogRecPtrIsInvalid(tle->begin) || tle->begin <= ptr) &&
-			(XLogRecPtrIsInvalid(tle->end) || ptr < tle->end))
+		if ((!XLogRecPtrIsValid(tle->begin) || tle->begin <= ptr) &&
+			(!XLogRecPtrIsValid(tle->end) || ptr < tle->end))
 		{
 			/* found it */
 			return tle->tli;
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 33369fbe23a..8a92b292e56 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -2547,7 +2547,7 @@ PrepareRedoAdd(FullTransactionId fxid, char *buf,
 	 * the record is added to TwoPhaseState and it should have no
 	 * corresponding file in pg_twophase.
 	 */
-	if (!XLogRecPtrIsInvalid(start_lsn))
+	if (XLogRecPtrIsValid(start_lsn))
 	{
 		char		path[MAXPGPATH];
 
@@ -2587,7 +2587,7 @@ PrepareRedoAdd(FullTransactionId fxid, char *buf,
 	gxact->owner = hdr->owner;
 	gxact->locking_backend = INVALID_PROC_NUMBER;
 	gxact->valid = false;
-	gxact->ondisk = XLogRecPtrIsInvalid(start_lsn);
+	gxact->ondisk = !XLogRecPtrIsValid(start_lsn);
 	gxact->inredo = true;		/* yes, added in redo */
 	strcpy(gxact->gid, gid);
 
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index fd91bcd68ec..4b827c17cfa 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -1761,7 +1761,7 @@ WALReadFromBuffers(char *dstbuf, XLogRecPtr startptr, Size count,
 	if (RecoveryInProgress() || tli != GetWALInsertionTimeLine())
 		return 0;
 
-	Assert(!XLogRecPtrIsInvalid(startptr));
+	Assert(XLogRecPtrIsValid(startptr));
 
 	/*
 	 * Caller should ensure that the requested data has been inserted into WAL
@@ -2716,7 +2716,7 @@ UpdateMinRecoveryPoint(XLogRecPtr lsn, bool force)
 	 * available is replayed in this case.  This also saves from extra locks
 	 * taken on the control file from the startup process.
 	 */
-	if (XLogRecPtrIsInvalid(LocalMinRecoveryPoint) && InRecovery)
+	if (!XLogRecPtrIsValid(LocalMinRecoveryPoint) && InRecovery)
 	{
 		updateMinRecoveryPoint = false;
 		return;
@@ -2728,7 +2728,7 @@ UpdateMinRecoveryPoint(XLogRecPtr lsn, bool force)
 	LocalMinRecoveryPoint = ControlFile->minRecoveryPoint;
 	LocalMinRecoveryPointTLI = ControlFile->minRecoveryPointTLI;
 
-	if (XLogRecPtrIsInvalid(LocalMinRecoveryPoint))
+	if (!XLogRecPtrIsValid(LocalMinRecoveryPoint))
 		updateMinRecoveryPoint = false;
 	else if (force || LocalMinRecoveryPoint < lsn)
 	{
@@ -3148,7 +3148,7 @@ XLogNeedsFlush(XLogRecPtr record)
 		 * which cannot update its local copy of minRecoveryPoint as long as
 		 * it has not replayed all WAL available when doing crash recovery.
 		 */
-		if (XLogRecPtrIsInvalid(LocalMinRecoveryPoint) && InRecovery)
+		if (!XLogRecPtrIsValid(LocalMinRecoveryPoint) && InRecovery)
 		{
 			updateMinRecoveryPoint = false;
 			return false;
@@ -3169,7 +3169,7 @@ XLogNeedsFlush(XLogRecPtr record)
 		 * process doing crash recovery, which should not update the control
 		 * file value if crash recovery is still running.
 		 */
-		if (XLogRecPtrIsInvalid(LocalMinRecoveryPoint))
+		if (!XLogRecPtrIsValid(LocalMinRecoveryPoint))
 			updateMinRecoveryPoint = false;
 
 		/* check again */
@@ -5934,7 +5934,7 @@ StartupXLOG(void)
 	 */
 	if (InRecovery &&
 		(EndOfLog < LocalMinRecoveryPoint ||
-		 !XLogRecPtrIsInvalid(ControlFile->backupStartPoint)))
+		 XLogRecPtrIsValid(ControlFile->backupStartPoint)))
 	{
 		/*
 		 * Ran off end of WAL before reaching end-of-backup WAL record, or
@@ -5944,7 +5944,7 @@ StartupXLOG(void)
 		 */
 		if (ArchiveRecoveryRequested || ControlFile->backupEndRequired)
 		{
-			if (!XLogRecPtrIsInvalid(ControlFile->backupStartPoint) || ControlFile->backupEndRequired)
+			if (XLogRecPtrIsValid(ControlFile->backupStartPoint) || ControlFile->backupEndRequired)
 				ereport(FATAL,
 						(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 						 errmsg("WAL ends before end of online backup"),
@@ -6046,7 +6046,7 @@ StartupXLOG(void)
 	 * (It's critical to first write an OVERWRITE_CONTRECORD message, which
 	 * we'll do as soon as we're open for writing new WAL.)
 	 */
-	if (!XLogRecPtrIsInvalid(missingContrecPtr))
+	if (XLogRecPtrIsValid(missingContrecPtr))
 	{
 		/*
 		 * We should only have a missingContrecPtr if we're not switching to a
@@ -6056,7 +6056,7 @@ StartupXLOG(void)
 		 * disregard.
 		 */
 		Assert(newTLI == endOfRecoveryInfo->lastRecTLI);
-		Assert(!XLogRecPtrIsInvalid(abortedRecPtr));
+		Assert(XLogRecPtrIsValid(abortedRecPtr));
 		EndOfLog = missingContrecPtr;
 	}
 
@@ -6160,9 +6160,9 @@ StartupXLOG(void)
 	LocalSetXLogInsertAllowed();
 
 	/* If necessary, write overwrite-contrecord before doing anything else */
-	if (!XLogRecPtrIsInvalid(abortedRecPtr))
+	if (XLogRecPtrIsValid(abortedRecPtr))
 	{
-		Assert(!XLogRecPtrIsInvalid(missingContrecPtr));
+		Assert(XLogRecPtrIsValid(missingContrecPtr));
 		CreateOverwriteContrecordRecord(abortedRecPtr, missingContrecPtr, newTLI);
 	}
 
@@ -7686,7 +7686,7 @@ CreateRestartPoint(int flags)
 	 * restartpoint. It's assumed that flushing the buffers will do that as a
 	 * side-effect.
 	 */
-	if (XLogRecPtrIsInvalid(lastCheckPointRecPtr) ||
+	if (!XLogRecPtrIsValid(lastCheckPointRecPtr) ||
 		lastCheckPoint.redo <= ControlFile->checkPointCopy.redo)
 	{
 		ereport(DEBUG2,
@@ -7929,7 +7929,7 @@ GetWALAvailability(XLogRecPtr targetLSN)
 	/*
 	 * slot does not reserve WAL. Either deactivated, or has never been active
 	 */
-	if (XLogRecPtrIsInvalid(targetLSN))
+	if (!XLogRecPtrIsValid(targetLSN))
 		return WALAVAIL_INVALID_LSN;
 
 	/*
@@ -8345,8 +8345,8 @@ xlog_redo(XLogReaderState *record)
 		 * never arrive.
 		 */
 		if (ArchiveRecoveryRequested &&
-			!XLogRecPtrIsInvalid(ControlFile->backupStartPoint) &&
-			XLogRecPtrIsInvalid(ControlFile->backupEndPoint))
+			XLogRecPtrIsValid(ControlFile->backupStartPoint) &&
+			!XLogRecPtrIsValid(ControlFile->backupEndPoint))
 			ereport(PANIC,
 					(errmsg("online backup was canceled, recovery cannot continue")));
 
diff --git a/src/backend/access/transam/xlogbackup.c b/src/backend/access/transam/xlogbackup.c
index cda4b38b7d6..78908ea32b3 100644
--- a/src/backend/access/transam/xlogbackup.c
+++ b/src/backend/access/transam/xlogbackup.c
@@ -78,8 +78,8 @@ build_backup_content(BackupState *state, bool ishistoryfile)
 	}
 
 	/* either both istartpoint and istarttli should be set, or neither */
-	Assert(XLogRecPtrIsInvalid(state->istartpoint) == (state->istarttli == 0));
-	if (!XLogRecPtrIsInvalid(state->istartpoint))
+	Assert(!XLogRecPtrIsValid(state->istartpoint) == (state->istarttli == 0));
+	if (XLogRecPtrIsValid(state->istartpoint))
 	{
 		appendStringInfo(result, "INCREMENTAL FROM LSN: %X/%08X\n",
 						 LSN_FORMAT_ARGS(state->istartpoint));
diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index dcc8d4f9c1b..aad16127e60 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -231,7 +231,7 @@ WALOpenSegmentInit(WALOpenSegment *seg, WALSegmentContext *segcxt,
 void
 XLogBeginRead(XLogReaderState *state, XLogRecPtr RecPtr)
 {
-	Assert(!XLogRecPtrIsInvalid(RecPtr));
+	Assert(XLogRecPtrIsValid(RecPtr));
 
 	ResetDecoder(state);
 
@@ -343,7 +343,7 @@ XLogNextRecord(XLogReaderState *state, char **errormsg)
 		 * XLogBeginRead() or XLogNextRecord(), and is the location of the
 		 * error.
 		 */
-		Assert(!XLogRecPtrIsInvalid(state->EndRecPtr));
+		Assert(XLogRecPtrIsValid(state->EndRecPtr));
 
 		return NULL;
 	}
@@ -1398,7 +1398,7 @@ XLogFindNextRecord(XLogReaderState *state, XLogRecPtr RecPtr)
 	XLogPageHeader header;
 	char	   *errormsg;
 
-	Assert(!XLogRecPtrIsInvalid(RecPtr));
+	Assert(XLogRecPtrIsValid(RecPtr));
 
 	/* Make sure ReadPageInternal() can't return XLREAD_WOULDBLOCK. */
 	state->nonblocking = false;
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index 3e3c4da01a2..84df67b07d2 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -772,7 +772,7 @@ InitWalRecovery(ControlFileData *ControlFile, bool *wasShutdown_ptr,
 		 * emit a log message when we continue initializing from a base
 		 * backup.
 		 */
-		if (!XLogRecPtrIsInvalid(ControlFile->backupStartPoint))
+		if (XLogRecPtrIsValid(ControlFile->backupStartPoint))
 			ereport(LOG,
 					errmsg("restarting backup recovery with redo LSN %X/%08X",
 						   LSN_FORMAT_ARGS(ControlFile->backupStartPoint)));
@@ -867,7 +867,7 @@ InitWalRecovery(ControlFileData *ControlFile, bool *wasShutdown_ptr,
 	 * The min recovery point should be part of the requested timeline's
 	 * history, too.
 	 */
-	if (!XLogRecPtrIsInvalid(ControlFile->minRecoveryPoint) &&
+	if (XLogRecPtrIsValid(ControlFile->minRecoveryPoint) &&
 		tliOfPointInHistory(ControlFile->minRecoveryPoint - 1, expectedTLEs) !=
 		ControlFile->minRecoveryPointTLI)
 		ereport(FATAL,
@@ -2193,7 +2193,7 @@ CheckRecoveryConsistency(void)
 	 * During crash recovery, we don't reach a consistent state until we've
 	 * replayed all the WAL.
 	 */
-	if (XLogRecPtrIsInvalid(minRecoveryPoint))
+	if (!XLogRecPtrIsValid(minRecoveryPoint))
 		return;
 
 	Assert(InArchiveRecovery);
@@ -2208,7 +2208,7 @@ CheckRecoveryConsistency(void)
 	/*
 	 * Have we reached the point where our base backup was completed?
 	 */
-	if (!XLogRecPtrIsInvalid(backupEndPoint) &&
+	if (XLogRecPtrIsValid(backupEndPoint) &&
 		backupEndPoint <= lastReplayedEndRecPtr)
 	{
 		XLogRecPtr	saveBackupStartPoint = backupStartPoint;
@@ -2414,7 +2414,7 @@ checkTimeLineSwitch(XLogRecPtr lsn, TimeLineID newTLI, TimeLineID prevTLI,
 	 * branched before the timeline the min recovery point is on, and you
 	 * attempt to do PITR to the new timeline.
 	 */
-	if (!XLogRecPtrIsInvalid(minRecoveryPoint) &&
+	if (XLogRecPtrIsValid(minRecoveryPoint) &&
 		lsn < minRecoveryPoint &&
 		newTLI > minRecoveryPointTLI)
 		ereport(PANIC,
@@ -3177,7 +3177,7 @@ ReadRecord(XLogPrefetcher *xlogprefetcher, int emode,
 			 * overwrite contrecord in the wrong place, breaking everything.
 			 */
 			if (!ArchiveRecoveryRequested &&
-				!XLogRecPtrIsInvalid(xlogreader->abortedRecPtr))
+				XLogRecPtrIsValid(xlogreader->abortedRecPtr))
 			{
 				abortedRecPtr = xlogreader->abortedRecPtr;
 				missingContrecPtr = xlogreader->missingContrecPtr;
diff --git a/src/backend/backup/backup_manifest.c b/src/backend/backup/backup_manifest.c
index d05252f383c..dd76c9b0b63 100644
--- a/src/backend/backup/backup_manifest.c
+++ b/src/backend/backup/backup_manifest.c
@@ -242,7 +242,7 @@ AddWALInfoToBackupManifest(backup_manifest_info *manifest, XLogRecPtr startptr,
 		 * entry->end is InvalidXLogRecPtr, it means that the timeline has not
 		 * yet ended.)
 		 */
-		if (!XLogRecPtrIsInvalid(entry->end) && entry->end < startptr)
+		if (XLogRecPtrIsValid(entry->end) && entry->end < startptr)
 			continue;
 
 		/*
@@ -274,7 +274,7 @@ AddWALInfoToBackupManifest(backup_manifest_info *manifest, XLogRecPtr startptr,
 			 * better have arrived at the expected starting TLI. If not,
 			 * something's gone horribly wrong.
 			 */
-			if (XLogRecPtrIsInvalid(entry->begin))
+			if (!XLogRecPtrIsValid(entry->begin))
 				ereport(ERROR,
 						errmsg("expected start timeline %u but found timeline %u",
 							   starttli, entry->tli));
diff --git a/src/backend/backup/basebackup_incremental.c b/src/backend/backup/basebackup_incremental.c
index a0d48ff0fef..852ab577045 100644
--- a/src/backend/backup/basebackup_incremental.c
+++ b/src/backend/backup/basebackup_incremental.c
@@ -519,7 +519,7 @@ PrepareForIncrementalBackup(IncrementalBackupInfo *ib,
 		if (!WalSummariesAreComplete(tli_wslist, tli_start_lsn, tli_end_lsn,
 									 &tli_missing_lsn))
 		{
-			if (XLogRecPtrIsInvalid(tli_missing_lsn))
+			if (!XLogRecPtrIsValid(tli_missing_lsn))
 				ereport(ERROR,
 						(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 						 errmsg("WAL summaries are required on timeline %u from %X/%08X to %X/%08X, but no summaries for that timeline and LSN range exist",
diff --git a/src/backend/backup/walsummary.c b/src/backend/backup/walsummary.c
index c7a2c65cc6a..2689eae3328 100644
--- a/src/backend/backup/walsummary.c
+++ b/src/backend/backup/walsummary.c
@@ -67,9 +67,9 @@ GetWalSummaries(TimeLineID tli, XLogRecPtr start_lsn, XLogRecPtr end_lsn)
 		/* Skip if it doesn't match the filter criteria. */
 		if (tli != 0 && tli != file_tli)
 			continue;
-		if (!XLogRecPtrIsInvalid(start_lsn) && start_lsn >= file_end_lsn)
+		if (XLogRecPtrIsValid(start_lsn) && start_lsn >= file_end_lsn)
 			continue;
-		if (!XLogRecPtrIsInvalid(end_lsn) && end_lsn <= file_start_lsn)
+		if (XLogRecPtrIsValid(end_lsn) && end_lsn <= file_start_lsn)
 			continue;
 
 		/* Add it to the list. */
@@ -111,9 +111,9 @@ FilterWalSummaries(List *wslist, TimeLineID tli,
 		/* Skip if it doesn't match the filter criteria. */
 		if (tli != 0 && tli != ws->tli)
 			continue;
-		if (!XLogRecPtrIsInvalid(start_lsn) && start_lsn > ws->end_lsn)
+		if (XLogRecPtrIsValid(start_lsn) && start_lsn > ws->end_lsn)
 			continue;
-		if (!XLogRecPtrIsInvalid(end_lsn) && end_lsn < ws->start_lsn)
+		if (XLogRecPtrIsValid(end_lsn) && end_lsn < ws->start_lsn)
 			continue;
 
 		/* Add it to the result list. */
diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c
index 1f45444b499..ccf238f665b 100644
--- a/src/backend/commands/subscriptioncmds.c
+++ b/src/backend/commands/subscriptioncmds.c
@@ -393,7 +393,7 @@ parse_subscription_options(ParseState *pstate, List *stmt_options,
 				lsn = DatumGetLSN(DirectFunctionCall1(pg_lsn_in,
 													  CStringGetDatum(lsn_str)));
 
-				if (XLogRecPtrIsInvalid(lsn))
+				if (!XLogRecPtrIsValid(lsn))
 					ereport(ERROR,
 							(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 							 errmsg("invalid WAL location (LSN): %s", lsn_str)));
@@ -1893,7 +1893,7 @@ AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt,
 				 * If the user sets subskiplsn, we do a sanity check to make
 				 * sure that the specified LSN is a probable value.
 				 */
-				if (!XLogRecPtrIsInvalid(opts.lsn))
+				if (XLogRecPtrIsValid(opts.lsn))
 				{
 					RepOriginId originid;
 					char		originname[NAMEDATALEN];
@@ -1905,7 +1905,7 @@ AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt,
 					remote_lsn = replorigin_get_progress(originid, false);
 
 					/* Check the given LSN is at least a future LSN */
-					if (!XLogRecPtrIsInvalid(remote_lsn) && opts.lsn < remote_lsn)
+					if (XLogRecPtrIsValid(remote_lsn) && opts.lsn < remote_lsn)
 						ereport(ERROR,
 								(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 								 errmsg("skip WAL location (LSN %X/%08X) must be greater than origin LSN %X/%08X",
diff --git a/src/backend/postmaster/walsummarizer.c b/src/backend/postmaster/walsummarizer.c
index e1f142f20c7..c4a888a081c 100644
--- a/src/backend/postmaster/walsummarizer.c
+++ b/src/backend/postmaster/walsummarizer.c
@@ -342,7 +342,7 @@ WalSummarizerMain(const void *startup_data, size_t startup_data_len)
 	 * If we discover that WAL summarization is not enabled, just exit.
 	 */
 	current_lsn = GetOldestUnsummarizedLSN(&current_tli, &exact);
-	if (XLogRecPtrIsInvalid(current_lsn))
+	if (!XLogRecPtrIsValid(current_lsn))
 		proc_exit(0);
 
 	/*
@@ -379,7 +379,7 @@ WalSummarizerMain(const void *startup_data, size_t startup_data_len)
 		 * only have to do this once per timeline switch, we probably wouldn't
 		 * save any significant amount of work in practice.
 		 */
-		if (current_tli != latest_tli && XLogRecPtrIsInvalid(switch_lsn))
+		if (current_tli != latest_tli && !XLogRecPtrIsValid(switch_lsn))
 		{
 			List	   *tles = readTimeLineHistory(latest_tli);
 
@@ -394,7 +394,7 @@ WalSummarizerMain(const void *startup_data, size_t startup_data_len)
 		 * on this timeline. Switch to the next timeline and go around again,
 		 * backing up to the exact switch point if we passed it.
 		 */
-		if (!XLogRecPtrIsInvalid(switch_lsn) && current_lsn >= switch_lsn)
+		if (XLogRecPtrIsValid(switch_lsn) && current_lsn >= switch_lsn)
 		{
 			/* Restart summarization from switch point. */
 			current_tli = switch_tli;
@@ -419,7 +419,7 @@ WalSummarizerMain(const void *startup_data, size_t startup_data_len)
 		end_of_summary_lsn = SummarizeWAL(current_tli,
 										  current_lsn, exact,
 										  switch_lsn, latest_lsn);
-		Assert(!XLogRecPtrIsInvalid(end_of_summary_lsn));
+		Assert(XLogRecPtrIsValid(end_of_summary_lsn));
 		Assert(end_of_summary_lsn >= current_lsn);
 
 		/*
@@ -923,7 +923,7 @@ SummarizeWAL(TimeLineID tli, XLogRecPtr start_lsn, bool exact,
 	private_data = (SummarizerReadLocalXLogPrivate *)
 		palloc0(sizeof(SummarizerReadLocalXLogPrivate));
 	private_data->tli = tli;
-	private_data->historic = !XLogRecPtrIsInvalid(switch_lsn);
+	private_data->historic = XLogRecPtrIsValid(switch_lsn);
 	private_data->read_upto = maximum_lsn;
 
 	/* Create xlogreader. */
@@ -971,7 +971,7 @@ SummarizeWAL(TimeLineID tli, XLogRecPtr start_lsn, bool exact,
 	else
 	{
 		summary_start_lsn = XLogFindNextRecord(xlogreader, start_lsn);
-		if (XLogRecPtrIsInvalid(summary_start_lsn))
+		if (!XLogRecPtrIsValid(summary_start_lsn))
 		{
 			/*
 			 * If we hit end-of-WAL while trying to find the next valid
@@ -1058,7 +1058,7 @@ SummarizeWAL(TimeLineID tli, XLogRecPtr start_lsn, bool exact,
 		/* We shouldn't go backward. */
 		Assert(summary_start_lsn <= xlogreader->EndRecPtr);
 
-		if (!XLogRecPtrIsInvalid(switch_lsn) &&
+		if (XLogRecPtrIsValid(switch_lsn) &&
 			xlogreader->ReadRecPtr >= switch_lsn)
 		{
 			/*
@@ -1180,7 +1180,7 @@ SummarizeWAL(TimeLineID tli, XLogRecPtr start_lsn, bool exact,
 		 * If we have a switch LSN and have reached it, stop before reading
 		 * the next record.
 		 */
-		if (!XLogRecPtrIsInvalid(switch_lsn) &&
+		if (XLogRecPtrIsValid(switch_lsn) &&
 			xlogreader->EndRecPtr >= switch_lsn)
 			break;
 	}
@@ -1723,7 +1723,7 @@ MaybeRemoveOldWalSummaries(void)
 			 * If the WAL doesn't exist any more, we can remove it if the file
 			 * modification time is old enough.
 			 */
-			if (XLogRecPtrIsInvalid(oldest_lsn) || ws->end_lsn <= oldest_lsn)
+			if (!XLogRecPtrIsValid(oldest_lsn) || ws->end_lsn <= oldest_lsn)
 				RemoveWalSummaryIfOlderThan(ws, cutoff_time);
 
 			/*
diff --git a/src/backend/replication/logical/applyparallelworker.c b/src/backend/replication/logical/applyparallelworker.c
index 14325581afc..baa68c1ab6c 100644
--- a/src/backend/replication/logical/applyparallelworker.c
+++ b/src/backend/replication/logical/applyparallelworker.c
@@ -299,7 +299,7 @@ pa_can_start(void)
 	 * STREAM START message, and it doesn't seem worth sending the extra eight
 	 * bytes with the STREAM START to enable parallelism for this case.
 	 */
-	if (!XLogRecPtrIsInvalid(MySubscription->skiplsn))
+	if (XLogRecPtrIsValid(MySubscription->skiplsn))
 		return false;
 
 	/*
@@ -1640,7 +1640,7 @@ pa_xact_finish(ParallelApplyWorkerInfo *winfo, XLogRecPtr remote_lsn)
 	 */
 	pa_wait_for_xact_finish(winfo);
 
-	if (!XLogRecPtrIsInvalid(remote_lsn))
+	if (XLogRecPtrIsValid(remote_lsn))
 		store_flush_position(remote_lsn, winfo->shared->last_commit_end);
 
 	pa_free_worker(winfo);
diff --git a/src/backend/replication/logical/launcher.c b/src/backend/replication/logical/launcher.c
index 95b5cae9a55..d735114bc59 100644
--- a/src/backend/replication/logical/launcher.c
+++ b/src/backend/replication/logical/launcher.c
@@ -1621,7 +1621,7 @@ pg_stat_get_subscription(PG_FUNCTION_ARGS)
 		else
 			nulls[3] = true;
 
-		if (XLogRecPtrIsInvalid(worker.last_lsn))
+		if (!XLogRecPtrIsValid(worker.last_lsn))
 			nulls[4] = true;
 		else
 			values[4] = LSNGetDatum(worker.last_lsn);
@@ -1633,7 +1633,7 @@ pg_stat_get_subscription(PG_FUNCTION_ARGS)
 			nulls[6] = true;
 		else
 			values[6] = TimestampTzGetDatum(worker.last_recv_time);
-		if (XLogRecPtrIsInvalid(worker.reply_lsn))
+		if (!XLogRecPtrIsValid(worker.reply_lsn))
 			nulls[7] = true;
 		else
 			values[7] = LSNGetDatum(worker.reply_lsn);
diff --git a/src/backend/replication/logical/logical.c b/src/backend/replication/logical/logical.c
index 93ed2eb368e..79717b52941 100644
--- a/src/backend/replication/logical/logical.c
+++ b/src/backend/replication/logical/logical.c
@@ -388,7 +388,7 @@ CreateInitDecodingContext(const char *plugin,
 	slot->data.plugin = plugin_name;
 	SpinLockRelease(&slot->mutex);
 
-	if (XLogRecPtrIsInvalid(restart_lsn))
+	if (!XLogRecPtrIsValid(restart_lsn))
 		ReplicationSlotReserveWal();
 	else
 	{
diff --git a/src/backend/replication/logical/logicalfuncs.c b/src/backend/replication/logical/logicalfuncs.c
index 25f890ddeed..d78e486bca6 100644
--- a/src/backend/replication/logical/logicalfuncs.c
+++ b/src/backend/replication/logical/logicalfuncs.c
@@ -229,7 +229,7 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin
 		 * Wait for specified streaming replication standby servers (if any)
 		 * to confirm receipt of WAL up to wait_for_wal_lsn.
 		 */
-		if (XLogRecPtrIsInvalid(upto_lsn))
+		if (!XLogRecPtrIsValid(upto_lsn))
 			wait_for_wal_lsn = end_of_wal;
 		else
 			wait_for_wal_lsn = Min(upto_lsn, end_of_wal);
diff --git a/src/backend/replication/logical/slotsync.c b/src/backend/replication/logical/slotsync.c
index b122d99b009..8b4afd87dc9 100644
--- a/src/backend/replication/logical/slotsync.c
+++ b/src/backend/replication/logical/slotsync.c
@@ -493,7 +493,7 @@ reserve_wal_for_local_slot(XLogRecPtr restart_lsn)
 	ReplicationSlot *slot = MyReplicationSlot;
 
 	Assert(slot != NULL);
-	Assert(XLogRecPtrIsInvalid(slot->data.restart_lsn));
+	Assert(!XLogRecPtrIsValid(slot->data.restart_lsn));
 
 	while (true)
 	{
@@ -899,8 +899,8 @@ synchronize_slots(WalReceiverConn *wrconn)
 		 * pg_replication_slots view, then we can avoid fetching RS_EPHEMERAL
 		 * slots in the first place.
 		 */
-		if ((XLogRecPtrIsInvalid(remote_slot->restart_lsn) ||
-			 XLogRecPtrIsInvalid(remote_slot->confirmed_lsn) ||
+		if ((!XLogRecPtrIsValid(remote_slot->restart_lsn) ||
+			 !XLogRecPtrIsValid(remote_slot->confirmed_lsn) ||
 			 !TransactionIdIsValid(remote_slot->catalog_xmin)) &&
 			remote_slot->invalidated == RS_INVAL_NONE)
 			pfree(remote_slot);
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index 7edd1c9cf06..e6da007b460 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -514,7 +514,7 @@ bool		InitializingApplyWorker = false;
  * by the user.
  */
 static XLogRecPtr skip_xact_finish_lsn = InvalidXLogRecPtr;
-#define is_skipping_changes() (unlikely(!XLogRecPtrIsInvalid(skip_xact_finish_lsn)))
+#define is_skipping_changes() (unlikely(XLogRecPtrIsValid(skip_xact_finish_lsn)))
 
 /* BufFile handle of the current streaming file */
 static BufFile *stream_fd = NULL;
@@ -4103,7 +4103,7 @@ LogicalRepApplyLoop(XLogRecPtr last_received)
 						 * due to a bug, we don't want to proceed as it can
 						 * incorrectly advance oldest_nonremovable_xid.
 						 */
-						if (XLogRecPtrIsInvalid(rdt_data.remote_lsn))
+						if (!XLogRecPtrIsValid(rdt_data.remote_lsn))
 							elog(ERROR, "cannot get the latest WAL position from the publisher");
 
 						maybe_advance_nonremovable_xid(&rdt_data, true);
@@ -4587,7 +4587,7 @@ wait_for_publisher_status(RetainDeadTuplesData *rdt_data,
 static void
 wait_for_local_flush(RetainDeadTuplesData *rdt_data)
 {
-	Assert(!XLogRecPtrIsInvalid(rdt_data->remote_lsn) &&
+	Assert(XLogRecPtrIsValid(rdt_data->remote_lsn) &&
 		   TransactionIdIsValid(rdt_data->candidate_xid));
 
 	/*
@@ -5993,7 +5993,7 @@ maybe_start_skipping_changes(XLogRecPtr finish_lsn)
 	 * function is called for every remote transaction and we assume that
 	 * skipping the transaction is not used often.
 	 */
-	if (likely(XLogRecPtrIsInvalid(MySubscription->skiplsn) ||
+	if (likely(!XLogRecPtrIsValid(MySubscription->skiplsn) ||
 			   MySubscription->skiplsn != finish_lsn))
 		return;
 
@@ -6039,7 +6039,7 @@ clear_subscription_skip_lsn(XLogRecPtr finish_lsn)
 	XLogRecPtr	myskiplsn = MySubscription->skiplsn;
 	bool		started_tx = false;
 
-	if (likely(XLogRecPtrIsInvalid(myskiplsn)) || am_parallel_apply_worker())
+	if (likely(!XLogRecPtrIsValid(myskiplsn)) || am_parallel_apply_worker())
 		return;
 
 	if (!IsTransactionState())
@@ -6135,7 +6135,7 @@ apply_error_callback(void *arg)
 			errcontext("processing remote data for replication origin \"%s\" during message type \"%s\"",
 					   errarg->origin_name,
 					   logicalrep_message_type(errarg->command));
-		else if (XLogRecPtrIsInvalid(errarg->finish_lsn))
+		else if (!XLogRecPtrIsValid(errarg->finish_lsn))
 			errcontext("processing remote data for replication origin \"%s\" during message type \"%s\" in transaction %u",
 					   errarg->origin_name,
 					   logicalrep_message_type(errarg->command),
@@ -6151,7 +6151,7 @@ apply_error_callback(void *arg)
 	{
 		if (errarg->remote_attnum < 0)
 		{
-			if (XLogRecPtrIsInvalid(errarg->finish_lsn))
+			if (!XLogRecPtrIsValid(errarg->finish_lsn))
 				errcontext("processing remote data for replication origin \"%s\" during message type \"%s\" for replication target relation \"%s.%s\" in transaction %u",
 						   errarg->origin_name,
 						   logicalrep_message_type(errarg->command),
@@ -6169,7 +6169,7 @@ apply_error_callback(void *arg)
 		}
 		else
 		{
-			if (XLogRecPtrIsInvalid(errarg->finish_lsn))
+			if (!XLogRecPtrIsValid(errarg->finish_lsn))
 				errcontext("processing remote data for replication origin \"%s\" during message type \"%s\" for replication target relation \"%s.%s\" column \"%s\" in transaction %u",
 						   errarg->origin_name,
 						   logicalrep_message_type(errarg->command),
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index 6363030808f..0cb93dc90f2 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -1730,7 +1730,7 @@ static inline bool
 CanInvalidateIdleSlot(ReplicationSlot *s)
 {
 	return (idle_replication_slot_timeout_secs != 0 &&
-			!XLogRecPtrIsInvalid(s->data.restart_lsn) &&
+			XLogRecPtrIsValid(s->data.restart_lsn) &&
 			s->inactive_since > 0 &&
 			!(RecoveryInProgress() && s->data.synced));
 }
@@ -2922,7 +2922,7 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
 	 * Don't need to wait for the standbys to catch up if they are already
 	 * beyond the specified WAL location.
 	 */
-	if (!XLogRecPtrIsInvalid(ss_oldest_flush_lsn) &&
+	if (XLogRecPtrIsValid(ss_oldest_flush_lsn) &&
 		ss_oldest_flush_lsn >= wait_for_lsn)
 		return true;
 
@@ -2993,7 +2993,7 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
 			break;
 		}
 
-		if (XLogRecPtrIsInvalid(restart_lsn) || restart_lsn < wait_for_lsn)
+		if (!XLogRecPtrIsValid(restart_lsn) || restart_lsn < wait_for_lsn)
 		{
 			/* Log a message if no active_pid for this physical slot */
 			if (inactive)
@@ -3012,7 +3012,7 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
 
 		Assert(restart_lsn >= wait_for_lsn);
 
-		if (XLogRecPtrIsInvalid(min_restart_lsn) ||
+		if (!XLogRecPtrIsValid(min_restart_lsn) ||
 			min_restart_lsn > restart_lsn)
 			min_restart_lsn = restart_lsn;
 
@@ -3031,7 +3031,7 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
 		return false;
 
 	/* The ss_oldest_flush_lsn must not retreat. */
-	Assert(XLogRecPtrIsInvalid(ss_oldest_flush_lsn) ||
+	Assert(!XLogRecPtrIsValid(ss_oldest_flush_lsn) ||
 		   min_restart_lsn >= ss_oldest_flush_lsn);
 
 	ss_oldest_flush_lsn = min_restart_lsn;
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index b8f21153e7b..5aecd5c6a50 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -46,7 +46,7 @@ create_physical_replication_slot(char *name, bool immediately_reserve,
 	if (immediately_reserve)
 	{
 		/* Reserve WAL as the user asked for it */
-		if (XLogRecPtrIsInvalid(restart_lsn))
+		if (!XLogRecPtrIsValid(restart_lsn))
 			ReplicationSlotReserveWal();
 		else
 			MyReplicationSlot->data.restart_lsn = restart_lsn;
@@ -357,7 +357,7 @@ pg_get_replication_slots(PG_FUNCTION_ARGS)
 				 *
 				 * If we do change it, save the state for safe_wal_size below.
 				 */
-				if (!XLogRecPtrIsInvalid(slot_contents.data.restart_lsn))
+				if (XLogRecPtrIsValid(slot_contents.data.restart_lsn))
 				{
 					int			pid;
 
@@ -407,7 +407,7 @@ pg_get_replication_slots(PG_FUNCTION_ARGS)
 		values[i++] = BoolGetDatum(slot_contents.data.two_phase);
 
 		if (slot_contents.data.two_phase &&
-			!XLogRecPtrIsInvalid(slot_contents.data.two_phase_at))
+			XLogRecPtrIsValid(slot_contents.data.two_phase_at))
 			values[i++] = LSNGetDatum(slot_contents.data.two_phase_at);
 		else
 			nulls[i++] = true;
@@ -523,7 +523,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 
 	CheckSlotPermissions();
 
-	if (XLogRecPtrIsInvalid(moveto))
+	if (!XLogRecPtrIsValid(moveto))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("invalid target WAL LSN")));
@@ -545,7 +545,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	ReplicationSlotAcquire(NameStr(*slotname), true, true);
 
 	/* A slot whose restart_lsn has never been reserved cannot be advanced */
-	if (XLogRecPtrIsInvalid(MyReplicationSlot->data.restart_lsn))
+	if (!XLogRecPtrIsValid(MyReplicationSlot->data.restart_lsn))
 		ereport(ERROR,
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 				 errmsg("replication slot \"%s\" cannot be advanced",
@@ -679,7 +679,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 						NameStr(*src_name))));
 
 	/* Copying non-reserved slot doesn't make sense */
-	if (XLogRecPtrIsInvalid(src_restart_lsn))
+	if (!XLogRecPtrIsValid(src_restart_lsn))
 		ereport(ERROR,
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 				 errmsg("cannot copy a replication slot that doesn't reserve WAL")));
@@ -785,7 +785,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 					 errdetail("The source replication slot was modified incompatibly during the copy operation.")));
 
 		/* The source slot must have a consistent snapshot */
-		if (src_islogical && XLogRecPtrIsInvalid(copy_confirmed_flush))
+		if (src_islogical && !XLogRecPtrIsValid(copy_confirmed_flush))
 			ereport(ERROR,
 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 					 errmsg("cannot copy unfinished logical replication slot \"%s\"",
@@ -840,7 +840,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 	/* All done.  Set up the return values */
 	values[0] = NameGetDatum(dst_name);
 	nulls[0] = false;
-	if (!XLogRecPtrIsInvalid(MyReplicationSlot->data.confirmed_flush))
+	if (XLogRecPtrIsValid(MyReplicationSlot->data.confirmed_flush))
 	{
 		values[1] = LSNGetDatum(MyReplicationSlot->data.confirmed_flush);
 		nulls[1] = false;
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index 32cf3a48b89..a0c79958fd5 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -493,7 +493,7 @@ SyncRepReleaseWaiters(void)
 	if (MyWalSnd->sync_standby_priority == 0 ||
 		(MyWalSnd->state != WALSNDSTATE_STREAMING &&
 		 MyWalSnd->state != WALSNDSTATE_STOPPING) ||
-		XLogRecPtrIsInvalid(MyWalSnd->flush))
+		!XLogRecPtrIsValid(MyWalSnd->flush))
 	{
 		announce_next_takeover = true;
 		return;
@@ -676,11 +676,11 @@ SyncRepGetOldestSyncRecPtr(XLogRecPtr *writePtr,
 		XLogRecPtr	flush = sync_standbys[i].flush;
 		XLogRecPtr	apply = sync_standbys[i].apply;
 
-		if (XLogRecPtrIsInvalid(*writePtr) || *writePtr > write)
+		if (!XLogRecPtrIsValid(*writePtr) || *writePtr > write)
 			*writePtr = write;
-		if (XLogRecPtrIsInvalid(*flushPtr) || *flushPtr > flush)
+		if (!XLogRecPtrIsValid(*flushPtr) || *flushPtr > flush)
 			*flushPtr = flush;
-		if (XLogRecPtrIsInvalid(*applyPtr) || *applyPtr > apply)
+		if (!XLogRecPtrIsValid(*applyPtr) || *applyPtr > apply)
 			*applyPtr = apply;
 	}
 }
@@ -799,7 +799,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 			continue;
 
 		/* Must have a valid flush position */
-		if (XLogRecPtrIsInvalid(stby->flush))
+		if (!XLogRecPtrIsValid(stby->flush))
 			continue;
 
 		/* OK, it's a candidate */
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index 7361ffc9dcf..2ee8fecee26 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1469,16 +1469,16 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	{
 		values[1] = CStringGetTextDatum(WalRcvGetStateString(state));
 
-		if (XLogRecPtrIsInvalid(receive_start_lsn))
+		if (!XLogRecPtrIsValid(receive_start_lsn))
 			nulls[2] = true;
 		else
 			values[2] = LSNGetDatum(receive_start_lsn);
 		values[3] = Int32GetDatum(receive_start_tli);
-		if (XLogRecPtrIsInvalid(written_lsn))
+		if (!XLogRecPtrIsValid(written_lsn))
 			nulls[4] = true;
 		else
 			values[4] = LSNGetDatum(written_lsn);
-		if (XLogRecPtrIsInvalid(flushed_lsn))
+		if (!XLogRecPtrIsValid(flushed_lsn))
 			nulls[5] = true;
 		else
 			values[5] = LSNGetDatum(flushed_lsn);
@@ -1491,7 +1491,7 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 			nulls[8] = true;
 		else
 			values[8] = TimestampTzGetDatum(last_receipt_time);
-		if (XLogRecPtrIsInvalid(latest_end_lsn))
+		if (!XLogRecPtrIsValid(latest_end_lsn))
 			nulls[9] = true;
 		else
 			values[9] = LSNGetDatum(latest_end_lsn);
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 548eafa7a73..b6dfb230d0d 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -529,7 +529,7 @@ ReadReplicationSlot(ReadReplicationSlotCmd *cmd)
 		i++;
 
 		/* start LSN */
-		if (!XLogRecPtrIsInvalid(slot_contents.data.restart_lsn))
+		if (XLogRecPtrIsValid(slot_contents.data.restart_lsn))
 		{
 			char		xloc[64];
 
@@ -541,7 +541,7 @@ ReadReplicationSlot(ReadReplicationSlotCmd *cmd)
 		i++;
 
 		/* timeline this WAL was produced on */
-		if (!XLogRecPtrIsInvalid(slot_contents.data.restart_lsn))
+		if (XLogRecPtrIsValid(slot_contents.data.restart_lsn))
 		{
 			TimeLineID	slots_position_timeline;
 			TimeLineID	current_timeline;
@@ -906,7 +906,7 @@ StartReplication(StartReplicationCmd *cmd)
 			 * that's older than the switchpoint, if it's still in the same
 			 * WAL segment.
 			 */
-			if (!XLogRecPtrIsInvalid(switchpoint) &&
+			if (XLogRecPtrIsValid(switchpoint) &&
 				switchpoint < cmd->startpoint)
 			{
 				ereport(ERROR,
@@ -1827,7 +1827,7 @@ WalSndWaitForWal(XLogRecPtr loc)
 	 * receipt of WAL up to RecentFlushPtr. This is particularly interesting
 	 * if we're far behind.
 	 */
-	if (!XLogRecPtrIsInvalid(RecentFlushPtr) &&
+	if (XLogRecPtrIsValid(RecentFlushPtr) &&
 		!NeedToWaitForWal(loc, RecentFlushPtr, &wait_event))
 		return RecentFlushPtr;
 
@@ -3597,7 +3597,7 @@ WalSndDone(WalSndSendDataCallback send_data)
 	 * flush location if valid, write otherwise. Tools like pg_receivewal will
 	 * usually (unless in synchronous mode) return an invalid flush location.
 	 */
-	replicatedPtr = XLogRecPtrIsInvalid(MyWalSnd->flush) ?
+	replicatedPtr = !XLogRecPtrIsValid(MyWalSnd->flush) ?
 		MyWalSnd->write : MyWalSnd->flush;
 
 	if (WalSndCaughtUp && sentPtr == replicatedPtr &&
@@ -4073,19 +4073,19 @@ pg_stat_get_wal_senders(PG_FUNCTION_ARGS)
 		{
 			values[1] = CStringGetTextDatum(WalSndGetStateString(state));
 
-			if (XLogRecPtrIsInvalid(sent_ptr))
+			if (!XLogRecPtrIsValid(sent_ptr))
 				nulls[2] = true;
 			values[2] = LSNGetDatum(sent_ptr);
 
-			if (XLogRecPtrIsInvalid(write))
+			if (!XLogRecPtrIsValid(write))
 				nulls[3] = true;
 			values[3] = LSNGetDatum(write);
 
-			if (XLogRecPtrIsInvalid(flush))
+			if (!XLogRecPtrIsValid(flush))
 				nulls[4] = true;
 			values[4] = LSNGetDatum(flush);
 
-			if (XLogRecPtrIsInvalid(apply))
+			if (!XLogRecPtrIsValid(apply))
 				nulls[5] = true;
 			values[5] = LSNGetDatum(apply);
 
@@ -4094,7 +4094,7 @@ pg_stat_get_wal_senders(PG_FUNCTION_ARGS)
 			 * which always returns an invalid flush location, as an
 			 * asynchronous standby.
 			 */
-			priority = XLogRecPtrIsInvalid(flush) ? 0 : priority;
+			priority = !XLogRecPtrIsValid(flush) ? 0 : priority;
 
 			if (writeLag < 0)
 				nulls[6] = true;
@@ -4165,7 +4165,7 @@ WalSndKeepalive(bool requestReply, XLogRecPtr writePtr)
 	/* construct the message... */
 	resetStringInfo(&output_message);
 	pq_sendbyte(&output_message, PqReplMsg_Keepalive);
-	pq_sendint64(&output_message, XLogRecPtrIsInvalid(writePtr) ? sentPtr : writePtr);
+	pq_sendint64(&output_message, !XLogRecPtrIsValid(writePtr) ? sentPtr : writePtr);
 	pq_sendint64(&output_message, GetCurrentTimestamp());
 	pq_sendbyte(&output_message, requestReply ? 1 : 0);
 
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index e8544acb784..1b5ef9ce10a 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -5545,7 +5545,7 @@ MarkBufferDirtyHint(Buffer buffer, bool buffer_std)
 			 * checksum here. That will happen when the page is written
 			 * sometime later in this checkpoint cycle.
 			 */
-			if (!XLogRecPtrIsInvalid(lsn))
+			if (XLogRecPtrIsValid(lsn))
 				PageSetLSN(page, lsn);
 		}
 
diff --git a/src/bin/pg_basebackup/pg_receivewal.c b/src/bin/pg_basebackup/pg_receivewal.c
index 289ca14dcfe..3e6f4a7fc48 100644
--- a/src/bin/pg_basebackup/pg_receivewal.c
+++ b/src/bin/pg_basebackup/pg_receivewal.c
@@ -192,7 +192,7 @@ stop_streaming(XLogRecPtr xlogpos, uint32 timeline, bool segment_finished)
 					LSN_FORMAT_ARGS(xlogpos),
 					timeline);
 
-	if (!XLogRecPtrIsInvalid(endpos) && endpos < xlogpos)
+	if (XLogRecPtrIsValid(endpos) && endpos < xlogpos)
 	{
 		if (verbose)
 			pg_log_info("stopped log streaming at %X/%08X (timeline %u)",
diff --git a/src/bin/pg_basebackup/pg_recvlogical.c b/src/bin/pg_basebackup/pg_recvlogical.c
index 7a4d1a2d2ca..6739784a993 100644
--- a/src/bin/pg_basebackup/pg_recvlogical.c
+++ b/src/bin/pg_basebackup/pg_recvlogical.c
@@ -1080,7 +1080,7 @@ prepareToTerminate(PGconn *conn, XLogRecPtr endpos, StreamStopReason reason,
 							LSN_FORMAT_ARGS(endpos));
 				break;
 			case STREAM_STOP_END_OF_WAL:
-				Assert(!XLogRecPtrIsInvalid(lsn));
+				Assert(XLogRecPtrIsValid(lsn));
 				pg_log_info("end position %X/%08X reached by WAL record at %X/%08X",
 							LSN_FORMAT_ARGS(endpos), LSN_FORMAT_ARGS(lsn));
 				break;
diff --git a/src/bin/pg_rewind/pg_rewind.c b/src/bin/pg_rewind/pg_rewind.c
index 1b953692b17..27c514f934a 100644
--- a/src/bin/pg_rewind/pg_rewind.c
+++ b/src/bin/pg_rewind/pg_rewind.c
@@ -850,9 +850,9 @@ progress_report(bool finished)
 static XLogRecPtr
 MinXLogRecPtr(XLogRecPtr a, XLogRecPtr b)
 {
-	if (XLogRecPtrIsInvalid(a))
+	if (!XLogRecPtrIsValid(a))
 		return b;
-	else if (XLogRecPtrIsInvalid(b))
+	else if (!XLogRecPtrIsValid(b))
 		return a;
 	else
 		return Min(a, b);
diff --git a/src/bin/pg_waldump/pg_waldump.c b/src/bin/pg_waldump/pg_waldump.c
index 13d3ec2f5be..19cf5461eac 100644
--- a/src/bin/pg_waldump/pg_waldump.c
+++ b/src/bin/pg_waldump/pg_waldump.c
@@ -637,7 +637,7 @@ XLogDumpDisplayStats(XLogDumpConfig *config, XLogStats *stats)
 	/*
 	 * Leave if no stats have been computed yet, as tracked by the end LSN.
 	 */
-	if (XLogRecPtrIsInvalid(stats->endptr))
+	if (!XLogRecPtrIsValid(stats->endptr))
 		return;
 
 	/*
@@ -1136,7 +1136,7 @@ main(int argc, char **argv)
 		/* parse position from file */
 		XLogFromFileName(fname, &private.timeline, &segno, WalSegSz);
 
-		if (XLogRecPtrIsInvalid(private.startptr))
+		if (!XLogRecPtrIsValid(private.startptr))
 			XLogSegNoOffsetToRecPtr(segno, 0, WalSegSz, private.startptr);
 		else if (!XLByteInSeg(private.startptr, segno, WalSegSz))
 		{
@@ -1147,7 +1147,7 @@ main(int argc, char **argv)
 		}
 
 		/* no second file specified, set end position */
-		if (!(optind + 1 < argc) && XLogRecPtrIsInvalid(private.endptr))
+		if (!(optind + 1 < argc) && !XLogRecPtrIsValid(private.endptr))
 			XLogSegNoOffsetToRecPtr(segno + 1, 0, WalSegSz, private.endptr);
 
 		/* parse ENDSEG if passed */
@@ -1170,7 +1170,7 @@ main(int argc, char **argv)
 				pg_fatal("ENDSEG %s is before STARTSEG %s",
 						 argv[optind + 1], argv[optind]);
 
-			if (XLogRecPtrIsInvalid(private.endptr))
+			if (!XLogRecPtrIsValid(private.endptr))
 				XLogSegNoOffsetToRecPtr(endsegno + 1, 0, WalSegSz,
 										private.endptr);
 
@@ -1192,7 +1192,7 @@ main(int argc, char **argv)
 		waldir = identify_target_directory(waldir, NULL);
 
 	/* we don't know what to print */
-	if (XLogRecPtrIsInvalid(private.startptr))
+	if (!XLogRecPtrIsValid(private.startptr))
 	{
 		pg_log_error("no start WAL location given");
 		goto bad_argument;
diff --git a/src/include/access/xlogdefs.h b/src/include/access/xlogdefs.h
index 2397fb24115..b16b2a1c8a3 100644
--- a/src/include/access/xlogdefs.h
+++ b/src/include/access/xlogdefs.h
@@ -26,8 +26,16 @@ typedef uint64 XLogRecPtr;
  * record can begin at zero.
  */
 #define InvalidXLogRecPtr	0
-#define XLogRecPtrIsInvalid(r)	((r) == InvalidXLogRecPtr)
+#define XLogRecPtrIsValid(r) ((r) != InvalidXLogRecPtr)
 
+/*
+ * New code should use XLogRecPtrIsValid() instead of XLogRecPtrIsInvalid()
+ * for consistency with the affirmative form of other *IsValid() macros and to
+ * avoid awkward double negative.
+ * This macro is retained for convenience of third-party code but could
+ * be deprecated in the future.
+ */
+#define XLogRecPtrIsInvalid(r)	((r) == InvalidXLogRecPtr)
 /*
  * First LSN to use for "fake" LSNs.
  *
-- 
2.34.1

v4-0002-Introduce-PG_DEPRECATED-and-deprecate-XLogRecPtrI.patchtext/x-diff; charset=us-asciiDownload
From 7d074e7f9329fa87fc8ef722df7095220b665751 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Mon, 3 Nov 2025 06:33:01 +0000
Subject: [PATCH v4 2/4] Introduce PG_DEPRECATED() and deprecate
 XLogRecPtrIsInvalid()

This commit creates a new macro PG_DEPRECATED() to mark a declaration as
deprecated with a custom message. The compiler will emit a warning when the
deprecated entity is used.

Then it makes use of this new macro to emit a deprecated message about
XLogRecPtrIsInvalid() as of version 24 (means until the new macro is available
on all the supported major versions).
---
 src/include/access/xlogdefs.h | 14 +++++++++++---
 src/include/c.h               | 15 +++++++++++++++
 2 files changed, 26 insertions(+), 3 deletions(-)
  46.3% src/include/access/
  53.6% src/include/

diff --git a/src/include/access/xlogdefs.h b/src/include/access/xlogdefs.h
index b16b2a1c8a3..2589a21083b 100644
--- a/src/include/access/xlogdefs.h
+++ b/src/include/access/xlogdefs.h
@@ -32,10 +32,18 @@ typedef uint64 XLogRecPtr;
  * New code should use XLogRecPtrIsValid() instead of XLogRecPtrIsInvalid()
  * for consistency with the affirmative form of other *IsValid() macros and to
  * avoid awkward double negative.
- * This macro is retained for convenience of third-party code but could
- * be deprecated in the future.
+ * This function is retained for convenience of third-party code but is/will be
+ * deprecated as of version 24.
  */
-#define XLogRecPtrIsInvalid(r)	((r) == InvalidXLogRecPtr)
+#if PG_VERSION_NUM >= 240000
+PG_DEPRECATED("use XLogRecPtrIsValid() instead")
+#endif
+static inline bool
+XLogRecPtrIsInvalid(XLogRecPtr ptr)
+{
+	return ptr == InvalidXLogRecPtr;
+}
+
 /*
  * First LSN to use for "fake" LSNs.
  *
diff --git a/src/include/c.h b/src/include/c.h
index 757dfff4782..60e13cd5d6d 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -227,6 +227,21 @@
 #define PG_USED_FOR_ASSERTS_ONLY pg_attribute_unused()
 #endif
 
+/*
+ * Mark a declaration as deprecated with a custom message. The compiler will
+ * emit a warning when the deprecated entity is used.
+ */
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L || \
+defined(__cplusplus) && __cplusplus >= 201402L
+#define PG_DEPRECATED(msg) [[deprecated(msg)]]
+#elif defined(__GNUC__) || defined(__clang__)
+#define PG_DEPRECATED(msg) __attribute__((deprecated(msg)))
+#elif defined(_MSC_VER)
+#define PG_DEPRECATED(msg) __declspec(deprecated(msg))
+#else
+#define PG_DEPRECATED(msg)
+#endif
+
 /* GCC supports format attributes */
 #if defined(__GNUC__)
 #define pg_attribute_format_arg(a) __attribute__((format_arg(a)))
-- 
2.34.1

v4-0003-Replace-InvalidXLogRecPtr-comparisons-with-XLogRe.patchtext/x-diff; charset=us-asciiDownload
From 17f441df6e04736aad844ff2c1ec6b9cdef8d6b3 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Wed, 29 Oct 2025 11:45:52 +0000
Subject: [PATCH v4 3/4] Replace InvalidXLogRecPtr comparisons with
 XLogRecPtrIsValid()

This commit ensures the XLogRecPtrIsValid() macro is used instead of direct
InvalidXLogRecPtr equality comparisons.
---
 src/backend/access/heap/rewriteheap.c         |  4 +-
 src/backend/access/heap/vacuumlazy.c          |  2 +-
 src/backend/access/transam/twophase.c         |  2 +-
 src/backend/access/transam/xlog.c             | 18 ++++-----
 src/backend/access/transam/xloginsert.c       |  4 +-
 src/backend/access/transam/xlogreader.c       |  2 +-
 src/backend/access/transam/xlogrecovery.c     |  8 ++--
 src/backend/access/transam/xlogutils.c        |  8 ++--
 src/backend/catalog/pg_subscription.c         |  4 +-
 src/backend/replication/logical/logical.c     | 30 +++++++--------
 .../replication/logical/logicalfuncs.c        |  4 +-
 src/backend/replication/logical/origin.c      | 18 ++++-----
 src/backend/replication/logical/proto.c       | 18 ++++-----
 .../replication/logical/reorderbuffer.c       | 38 +++++++++----------
 src/backend/replication/logical/snapbuild.c   | 14 +++----
 src/backend/replication/slot.c                | 18 ++++-----
 src/backend/replication/slotfuncs.c           |  6 +--
 src/backend/replication/walsender.c           |  6 +--
 src/bin/pg_basebackup/pg_receivewal.c         |  6 +--
 src/bin/pg_basebackup/pg_recvlogical.c        | 10 ++---
 src/bin/pg_waldump/pg_waldump.c               |  4 +-
 src/include/access/xlogdefs.h                 |  2 +-
 22 files changed, 113 insertions(+), 113 deletions(-)
  19.4% src/backend/access/transam/
  54.8% src/backend/replication/logical/
  12.3% src/backend/replication/
   3.6% src/backend/
   7.6% src/bin/pg_basebackup/

diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c
index 8061e92f044..66ab48f0fe0 100644
--- a/src/backend/access/heap/rewriteheap.c
+++ b/src/backend/access/heap/rewriteheap.c
@@ -1169,7 +1169,7 @@ CheckPointLogicalRewriteHeap(void)
 	cutoff = ReplicationSlotsComputeLogicalRestartLSN();
 
 	/* don't start earlier than the restart lsn */
-	if (cutoff != InvalidXLogRecPtr && redo < cutoff)
+	if (XLogRecPtrIsValid(cutoff) && redo < cutoff)
 		cutoff = redo;
 
 	mappings_dir = AllocateDir(PG_LOGICAL_MAPPINGS_DIR);
@@ -1204,7 +1204,7 @@ CheckPointLogicalRewriteHeap(void)
 
 		lsn = ((uint64) hi) << 32 | lo;
 
-		if (lsn < cutoff || cutoff == InvalidXLogRecPtr)
+		if (lsn < cutoff || !XLogRecPtrIsValid(cutoff))
 		{
 			elog(DEBUG1, "removing logical rewrite file \"%s\"", path);
 			if (unlink(path) < 0)
diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c
index d2b031fdd06..27fba1e3dd4 100644
--- a/src/backend/access/heap/vacuumlazy.c
+++ b/src/backend/access/heap/vacuumlazy.c
@@ -1900,7 +1900,7 @@ lazy_scan_new_or_empty(LVRelState *vacrel, Buffer buf, BlockNumber blkno,
 			 * WAL-logged, and if not, do that now.
 			 */
 			if (RelationNeedsWAL(vacrel->rel) &&
-				PageGetLSN(page) == InvalidXLogRecPtr)
+				!XLogRecPtrIsValid(PageGetLSN(page)))
 				log_newpage_buffer(buf, true);
 
 			PageSetAllVisible(page);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 8a92b292e56..89d0bfa7760 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -2198,7 +2198,7 @@ ProcessTwoPhaseBuffer(FullTransactionId fxid,
 	Assert(LWLockHeldByMeInMode(TwoPhaseStateLock, LW_EXCLUSIVE));
 
 	if (!fromdisk)
-		Assert(prepare_start_lsn != InvalidXLogRecPtr);
+		Assert(XLogRecPtrIsValid(prepare_start_lsn));
 
 	/* Already processed? */
 	if (TransactionIdDidCommit(XidFromFullTransactionId(fxid)) ||
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 4b827c17cfa..b2f53022805 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -848,7 +848,7 @@ XLogInsertRecord(XLogRecData *rdata,
 
 		if (doPageWrites &&
 			(!prevDoPageWrites ||
-			 (fpw_lsn != InvalidXLogRecPtr && fpw_lsn <= RedoRecPtr)))
+			 (XLogRecPtrIsValid(fpw_lsn) && fpw_lsn <= RedoRecPtr)))
 		{
 			/*
 			 * Oops, some buffer now needs to be backed up that the caller
@@ -882,7 +882,7 @@ XLogInsertRecord(XLogRecData *rdata,
 		 * Those checks are only needed for records that can contain buffer
 		 * references, and an XLOG_SWITCH record never does.
 		 */
-		Assert(fpw_lsn == InvalidXLogRecPtr);
+		Assert(!XLogRecPtrIsValid(fpw_lsn));
 		WALInsertLockAcquireExclusive();
 		inserted = ReserveXLogSwitch(&StartPos, &EndPos, &rechdr->xl_prev);
 	}
@@ -897,7 +897,7 @@ XLogInsertRecord(XLogRecData *rdata,
 		 * not check RedoRecPtr before inserting the record; we just need to
 		 * update it afterwards.
 		 */
-		Assert(fpw_lsn == InvalidXLogRecPtr);
+		Assert(!XLogRecPtrIsValid(fpw_lsn));
 		WALInsertLockAcquireExclusive();
 		ReserveXLogInsertLocation(rechdr->xl_tot_len, &StartPos, &EndPos,
 								  &rechdr->xl_prev);
@@ -1602,7 +1602,7 @@ WaitXLogInsertionsToFinish(XLogRecPtr upto)
 			 */
 		} while (insertingat < upto);
 
-		if (insertingat != InvalidXLogRecPtr && insertingat < finishedUpto)
+		if (XLogRecPtrIsValid(insertingat) && insertingat < finishedUpto)
 			finishedUpto = insertingat;
 	}
 
@@ -7356,7 +7356,7 @@ CreateCheckPoint(int flags)
 	 * Update the average distance between checkpoints if the prior checkpoint
 	 * exists.
 	 */
-	if (PriorRedoPtr != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(PriorRedoPtr))
 		UpdateCheckPointDistanceEstimate(RedoRecPtr - PriorRedoPtr);
 
 	INJECTION_POINT("checkpoint-before-old-wal-removal", NULL);
@@ -7804,7 +7804,7 @@ CreateRestartPoint(int flags)
 	 * Update the average distance between checkpoints/restartpoints if the
 	 * prior checkpoint exists.
 	 */
-	if (PriorRedoPtr != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(PriorRedoPtr))
 		UpdateCheckPointDistanceEstimate(RedoRecPtr - PriorRedoPtr);
 
 	/*
@@ -8011,7 +8011,7 @@ KeepLogSeg(XLogRecPtr recptr, XLogSegNo *logSegNo)
 
 	/* Calculate how many segments are kept by slots. */
 	keep = XLogGetReplicationSlotMinimumLSN();
-	if (keep != InvalidXLogRecPtr && keep < recptr)
+	if (XLogRecPtrIsValid(keep) && keep < recptr)
 	{
 		XLByteToSeg(keep, segno, wal_segment_size);
 
@@ -8038,7 +8038,7 @@ KeepLogSeg(XLogRecPtr recptr, XLogSegNo *logSegNo)
 	 * summarized.
 	 */
 	keep = GetOldestUnsummarizedLSN(NULL, NULL);
-	if (keep != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(keep))
 	{
 		XLogSegNo	unsummarized_segno;
 
@@ -8596,7 +8596,7 @@ xlog_redo(XLogReaderState *record)
 			LocalMinRecoveryPoint = ControlFile->minRecoveryPoint;
 			LocalMinRecoveryPointTLI = ControlFile->minRecoveryPointTLI;
 		}
-		if (LocalMinRecoveryPoint != InvalidXLogRecPtr && LocalMinRecoveryPoint < lsn)
+		if (XLogRecPtrIsValid(LocalMinRecoveryPoint) && LocalMinRecoveryPoint < lsn)
 		{
 			TimeLineID	replayTLI;
 
diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c
index 58cb4b1b00c..a56d5a55282 100644
--- a/src/backend/access/transam/xloginsert.c
+++ b/src/backend/access/transam/xloginsert.c
@@ -528,7 +528,7 @@ XLogInsert(RmgrId rmid, uint8 info)
 
 		EndPos = XLogInsertRecord(rdt, fpw_lsn, curinsert_flags, num_fpi,
 								  fpi_bytes, topxid_included);
-	} while (EndPos == InvalidXLogRecPtr);
+	} while (!XLogRecPtrIsValid(EndPos));
 
 	XLogResetInsertion();
 
@@ -639,7 +639,7 @@ XLogRecordAssemble(RmgrId rmid, uint8 info,
 			needs_backup = (page_lsn <= RedoRecPtr);
 			if (!needs_backup)
 			{
-				if (*fpw_lsn == InvalidXLogRecPtr || page_lsn < *fpw_lsn)
+				if (!XLogRecPtrIsValid(*fpw_lsn) || page_lsn < *fpw_lsn)
 					*fpw_lsn = page_lsn;
 			}
 		}
diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index aad16127e60..755f351143a 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -558,7 +558,7 @@ XLogDecodeNextRecord(XLogReaderState *state, bool nonblocking)
 
 	RecPtr = state->NextRecPtr;
 
-	if (state->DecodeRecPtr != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(state->DecodeRecPtr))
 	{
 		/* read the record after the one we just read */
 
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index 84df67b07d2..f1e90076576 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -757,9 +757,9 @@ InitWalRecovery(ControlFileData *ControlFile, bool *wasShutdown_ptr,
 		 * end-of-backup record), and we can enter archive recovery directly.
 		 */
 		if (ArchiveRecoveryRequested &&
-			(ControlFile->minRecoveryPoint != InvalidXLogRecPtr ||
+			(XLogRecPtrIsValid(ControlFile->minRecoveryPoint) ||
 			 ControlFile->backupEndRequired ||
-			 ControlFile->backupEndPoint != InvalidXLogRecPtr ||
+			 XLogRecPtrIsValid(ControlFile->backupEndPoint) ||
 			 ControlFile->state == DB_SHUTDOWNED))
 		{
 			InArchiveRecovery = true;
@@ -3151,7 +3151,7 @@ ReadRecord(XLogPrefetcher *xlogprefetcher, int emode,
 	/* Pass through parameters to XLogPageRead */
 	private->fetching_ckpt = fetching_ckpt;
 	private->emode = emode;
-	private->randAccess = (xlogreader->ReadRecPtr == InvalidXLogRecPtr);
+	private->randAccess = (!XLogRecPtrIsValid(xlogreader->ReadRecPtr));
 	private->replayTLI = replayTLI;
 
 	/* This is the first attempt to read this page. */
@@ -4336,7 +4336,7 @@ XLogFileReadAnyTLI(XLogSegNo segno, XLogSource source)
 		 * Skip scanning the timeline ID that the logfile segment to read
 		 * doesn't belong to
 		 */
-		if (hent->begin != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(hent->begin))
 		{
 			XLogSegNo	beginseg = 0;
 
diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c
index 38176d9688e..ce2a3e42146 100644
--- a/src/backend/access/transam/xlogutils.c
+++ b/src/backend/access/transam/xlogutils.c
@@ -710,7 +710,7 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage,
 	const XLogRecPtr lastReadPage = (state->seg.ws_segno *
 									 state->segcxt.ws_segsize + state->segoff);
 
-	Assert(wantPage != InvalidXLogRecPtr && wantPage % XLOG_BLCKSZ == 0);
+	Assert(XLogRecPtrIsValid(wantPage) && wantPage % XLOG_BLCKSZ == 0);
 	Assert(wantLength <= XLOG_BLCKSZ);
 	Assert(state->readLen == 0 || state->readLen <= XLOG_BLCKSZ);
 	Assert(currTLI != 0);
@@ -741,7 +741,7 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage,
 	 */
 	if (state->currTLI == currTLI && wantPage >= lastReadPage)
 	{
-		Assert(state->currTLIValidUntil == InvalidXLogRecPtr);
+		Assert(!XLogRecPtrIsValid(state->currTLIValidUntil));
 		return;
 	}
 
@@ -750,7 +750,7 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage,
 	 * timeline and the timeline we're reading from is valid until the end of
 	 * the current segment we can just keep reading.
 	 */
-	if (state->currTLIValidUntil != InvalidXLogRecPtr &&
+	if (XLogRecPtrIsValid(state->currTLIValidUntil) &&
 		state->currTLI != currTLI &&
 		state->currTLI != 0 &&
 		((wantPage + wantLength) / state->segcxt.ws_segsize) <
@@ -790,7 +790,7 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage,
 		state->currTLIValidUntil = tliSwitchPoint(state->currTLI, timelineHistory,
 												  &state->nextTLI);
 
-		Assert(state->currTLIValidUntil == InvalidXLogRecPtr ||
+		Assert(!XLogRecPtrIsValid(state->currTLIValidUntil) ||
 			   wantPage + wantLength < state->currTLIValidUntil);
 
 		list_free_deep(timelineHistory);
diff --git a/src/backend/catalog/pg_subscription.c b/src/backend/catalog/pg_subscription.c
index 15b233a37d8..d836ea80b4d 100644
--- a/src/backend/catalog/pg_subscription.c
+++ b/src/backend/catalog/pg_subscription.c
@@ -293,7 +293,7 @@ AddSubscriptionRelState(Oid subid, Oid relid, char state,
 	values[Anum_pg_subscription_rel_srsubid - 1] = ObjectIdGetDatum(subid);
 	values[Anum_pg_subscription_rel_srrelid - 1] = ObjectIdGetDatum(relid);
 	values[Anum_pg_subscription_rel_srsubstate - 1] = CharGetDatum(state);
-	if (sublsn != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(sublsn))
 		values[Anum_pg_subscription_rel_srsublsn - 1] = LSNGetDatum(sublsn);
 	else
 		nulls[Anum_pg_subscription_rel_srsublsn - 1] = true;
@@ -366,7 +366,7 @@ UpdateSubscriptionRelState(Oid subid, Oid relid, char state,
 	values[Anum_pg_subscription_rel_srsubstate - 1] = CharGetDatum(state);
 
 	replaces[Anum_pg_subscription_rel_srsublsn - 1] = true;
-	if (sublsn != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(sublsn))
 		values[Anum_pg_subscription_rel_srsublsn - 1] = LSNGetDatum(sublsn);
 	else
 		nulls[Anum_pg_subscription_rel_srsublsn - 1] = true;
diff --git a/src/backend/replication/logical/logical.c b/src/backend/replication/logical/logical.c
index 79717b52941..866f92cf799 100644
--- a/src/backend/replication/logical/logical.c
+++ b/src/backend/replication/logical/logical.c
@@ -546,9 +546,9 @@ CreateDecodingContext(XLogRecPtr start_lsn,
 
 	/* slot must be valid to allow decoding */
 	Assert(slot->data.invalidated == RS_INVAL_NONE);
-	Assert(slot->data.restart_lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(slot->data.restart_lsn));
 
-	if (start_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(start_lsn))
 	{
 		/* continue from last position */
 		start_lsn = slot->data.confirmed_flush;
@@ -757,7 +757,7 @@ output_plugin_error_callback(void *arg)
 	LogicalErrorCallbackState *state = (LogicalErrorCallbackState *) arg;
 
 	/* not all callbacks have an associated LSN  */
-	if (state->report_location != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(state->report_location))
 		errcontext("slot \"%s\", output plugin \"%s\", in the %s callback, associated LSN %X/%08X",
 				   NameStr(state->ctx->slot->data.name),
 				   NameStr(state->ctx->slot->data.plugin),
@@ -1711,7 +1711,7 @@ LogicalIncreaseXminForSlot(XLogRecPtr current_lsn, TransactionId xmin)
 	 * Only increase if the previous values have been applied, otherwise we
 	 * might never end up updating if the receiver acks too slowly.
 	 */
-	else if (slot->candidate_xmin_lsn == InvalidXLogRecPtr)
+	else if (!XLogRecPtrIsValid(slot->candidate_xmin_lsn))
 	{
 		slot->candidate_catalog_xmin = xmin;
 		slot->candidate_xmin_lsn = current_lsn;
@@ -1749,8 +1749,8 @@ LogicalIncreaseRestartDecodingForSlot(XLogRecPtr current_lsn, XLogRecPtr restart
 	slot = MyReplicationSlot;
 
 	Assert(slot != NULL);
-	Assert(restart_lsn != InvalidXLogRecPtr);
-	Assert(current_lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(restart_lsn));
+	Assert(XLogRecPtrIsValid(current_lsn));
 
 	SpinLockAcquire(&slot->mutex);
 
@@ -1779,7 +1779,7 @@ LogicalIncreaseRestartDecodingForSlot(XLogRecPtr current_lsn, XLogRecPtr restart
 	 * might never end up updating if the receiver acks too slowly. A missed
 	 * value here will just cause some extra effort after reconnecting.
 	 */
-	else if (slot->candidate_restart_valid == InvalidXLogRecPtr)
+	else if (!XLogRecPtrIsValid(slot->candidate_restart_valid))
 	{
 		slot->candidate_restart_valid = current_lsn;
 		slot->candidate_restart_lsn = restart_lsn;
@@ -1819,11 +1819,11 @@ LogicalIncreaseRestartDecodingForSlot(XLogRecPtr current_lsn, XLogRecPtr restart
 void
 LogicalConfirmReceivedLocation(XLogRecPtr lsn)
 {
-	Assert(lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(lsn));
 
 	/* Do an unlocked check for candidate_lsn first. */
-	if (MyReplicationSlot->candidate_xmin_lsn != InvalidXLogRecPtr ||
-		MyReplicationSlot->candidate_restart_valid != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(MyReplicationSlot->candidate_xmin_lsn) ||
+		XLogRecPtrIsValid(MyReplicationSlot->candidate_restart_valid))
 	{
 		bool		updated_xmin = false;
 		bool		updated_restart = false;
@@ -1849,7 +1849,7 @@ LogicalConfirmReceivedLocation(XLogRecPtr lsn)
 			MyReplicationSlot->data.confirmed_flush = lsn;
 
 		/* if we're past the location required for bumping xmin, do so */
-		if (MyReplicationSlot->candidate_xmin_lsn != InvalidXLogRecPtr &&
+		if (XLogRecPtrIsValid(MyReplicationSlot->candidate_xmin_lsn) &&
 			MyReplicationSlot->candidate_xmin_lsn <= lsn)
 		{
 			/*
@@ -1871,10 +1871,10 @@ LogicalConfirmReceivedLocation(XLogRecPtr lsn)
 			}
 		}
 
-		if (MyReplicationSlot->candidate_restart_valid != InvalidXLogRecPtr &&
+		if (XLogRecPtrIsValid(MyReplicationSlot->candidate_restart_valid) &&
 			MyReplicationSlot->candidate_restart_valid <= lsn)
 		{
-			Assert(MyReplicationSlot->candidate_restart_lsn != InvalidXLogRecPtr);
+			Assert(XLogRecPtrIsValid(MyReplicationSlot->candidate_restart_lsn));
 
 			MyReplicationSlot->data.restart_lsn = MyReplicationSlot->candidate_restart_lsn;
 			MyReplicationSlot->candidate_restart_lsn = InvalidXLogRecPtr;
@@ -2089,7 +2089,7 @@ LogicalSlotAdvanceAndCheckSnapState(XLogRecPtr moveto,
 	ResourceOwner old_resowner PG_USED_FOR_ASSERTS_ONLY = CurrentResourceOwner;
 	XLogRecPtr	retlsn;
 
-	Assert(moveto != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(moveto));
 
 	if (found_consistent_snapshot)
 		*found_consistent_snapshot = false;
@@ -2163,7 +2163,7 @@ LogicalSlotAdvanceAndCheckSnapState(XLogRecPtr moveto,
 		if (found_consistent_snapshot && DecodingContextReady(ctx))
 			*found_consistent_snapshot = true;
 
-		if (ctx->reader->EndRecPtr != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(ctx->reader->EndRecPtr))
 		{
 			LogicalConfirmReceivedLocation(moveto);
 
diff --git a/src/backend/replication/logical/logicalfuncs.c b/src/backend/replication/logical/logicalfuncs.c
index d78e486bca6..49b2aef3c74 100644
--- a/src/backend/replication/logical/logicalfuncs.c
+++ b/src/backend/replication/logical/logicalfuncs.c
@@ -276,7 +276,7 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin
 			}
 
 			/* check limits */
-			if (upto_lsn != InvalidXLogRecPtr &&
+			if (XLogRecPtrIsValid(upto_lsn) &&
 				upto_lsn <= ctx->reader->EndRecPtr)
 				break;
 			if (upto_nchanges != 0 &&
@@ -289,7 +289,7 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin
 		 * Next time, start where we left off. (Hunting things, the family
 		 * business..)
 		 */
-		if (ctx->reader->EndRecPtr != InvalidXLogRecPtr && confirm)
+		if (XLogRecPtrIsValid(ctx->reader->EndRecPtr) && confirm)
 		{
 			LogicalConfirmReceivedLocation(ctx->reader->EndRecPtr);
 
diff --git a/src/backend/replication/logical/origin.c b/src/backend/replication/logical/origin.c
index bcd5d9aad62..4632aa8115d 100644
--- a/src/backend/replication/logical/origin.c
+++ b/src/backend/replication/logical/origin.c
@@ -984,8 +984,8 @@ replorigin_advance(RepOriginId node,
 		/* initialize new slot */
 		LWLockAcquire(&free_state->lock, LW_EXCLUSIVE);
 		replication_state = free_state;
-		Assert(replication_state->remote_lsn == InvalidXLogRecPtr);
-		Assert(replication_state->local_lsn == InvalidXLogRecPtr);
+		Assert(!XLogRecPtrIsValid(replication_state->remote_lsn));
+		Assert(!XLogRecPtrIsValid(replication_state->local_lsn));
 		replication_state->roident = node;
 	}
 
@@ -1020,7 +1020,7 @@ replorigin_advance(RepOriginId node,
 	 */
 	if (go_backward || replication_state->remote_lsn < remote_commit)
 		replication_state->remote_lsn = remote_commit;
-	if (local_commit != InvalidXLogRecPtr &&
+	if (XLogRecPtrIsValid(local_commit) &&
 		(go_backward || replication_state->local_lsn < local_commit))
 		replication_state->local_lsn = local_commit;
 	LWLockRelease(&replication_state->lock);
@@ -1064,7 +1064,7 @@ replorigin_get_progress(RepOriginId node, bool flush)
 
 	LWLockRelease(ReplicationOriginLock);
 
-	if (flush && local_lsn != InvalidXLogRecPtr)
+	if (flush && XLogRecPtrIsValid(local_lsn))
 		XLogFlush(local_lsn);
 
 	return remote_lsn;
@@ -1197,8 +1197,8 @@ replorigin_session_setup(RepOriginId node, int acquired_by)
 
 		/* initialize new slot */
 		session_replication_state = &replication_states[free_slot];
-		Assert(session_replication_state->remote_lsn == InvalidXLogRecPtr);
-		Assert(session_replication_state->local_lsn == InvalidXLogRecPtr);
+		Assert(!XLogRecPtrIsValid(session_replication_state->remote_lsn));
+		Assert(!XLogRecPtrIsValid(session_replication_state->local_lsn));
 		session_replication_state->roident = node;
 	}
 
@@ -1282,7 +1282,7 @@ replorigin_session_get_progress(bool flush)
 	local_lsn = session_replication_state->local_lsn;
 	LWLockRelease(&session_replication_state->lock);
 
-	if (flush && local_lsn != InvalidXLogRecPtr)
+	if (flush && XLogRecPtrIsValid(local_lsn))
 		XLogFlush(local_lsn);
 
 	return remote_lsn;
@@ -1454,7 +1454,7 @@ pg_replication_origin_session_progress(PG_FUNCTION_ARGS)
 
 	remote_lsn = replorigin_session_get_progress(flush);
 
-	if (remote_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(remote_lsn))
 		PG_RETURN_NULL();
 
 	PG_RETURN_LSN(remote_lsn);
@@ -1543,7 +1543,7 @@ pg_replication_origin_progress(PG_FUNCTION_ARGS)
 
 	remote_lsn = replorigin_get_progress(roident, flush);
 
-	if (remote_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(remote_lsn))
 		PG_RETURN_NULL();
 
 	PG_RETURN_LSN(remote_lsn);
diff --git a/src/backend/replication/logical/proto.c b/src/backend/replication/logical/proto.c
index ed62888764c..f0a913892b9 100644
--- a/src/backend/replication/logical/proto.c
+++ b/src/backend/replication/logical/proto.c
@@ -64,7 +64,7 @@ logicalrep_read_begin(StringInfo in, LogicalRepBeginData *begin_data)
 {
 	/* read fields */
 	begin_data->final_lsn = pq_getmsgint64(in);
-	if (begin_data->final_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(begin_data->final_lsn))
 		elog(ERROR, "final_lsn not set in begin message");
 	begin_data->committime = pq_getmsgint64(in);
 	begin_data->xid = pq_getmsgint(in, 4);
@@ -135,10 +135,10 @@ logicalrep_read_begin_prepare(StringInfo in, LogicalRepPreparedTxnData *begin_da
 {
 	/* read fields */
 	begin_data->prepare_lsn = pq_getmsgint64(in);
-	if (begin_data->prepare_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(begin_data->prepare_lsn))
 		elog(ERROR, "prepare_lsn not set in begin prepare message");
 	begin_data->end_lsn = pq_getmsgint64(in);
-	if (begin_data->end_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(begin_data->end_lsn))
 		elog(ERROR, "end_lsn not set in begin prepare message");
 	begin_data->prepare_time = pq_getmsgint64(in);
 	begin_data->xid = pq_getmsgint(in, 4);
@@ -207,10 +207,10 @@ logicalrep_read_prepare_common(StringInfo in, char *msgtype,
 
 	/* read fields */
 	prepare_data->prepare_lsn = pq_getmsgint64(in);
-	if (prepare_data->prepare_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(prepare_data->prepare_lsn))
 		elog(ERROR, "prepare_lsn is not set in %s message", msgtype);
 	prepare_data->end_lsn = pq_getmsgint64(in);
-	if (prepare_data->end_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(prepare_data->end_lsn))
 		elog(ERROR, "end_lsn is not set in %s message", msgtype);
 	prepare_data->prepare_time = pq_getmsgint64(in);
 	prepare_data->xid = pq_getmsgint(in, 4);
@@ -274,10 +274,10 @@ logicalrep_read_commit_prepared(StringInfo in, LogicalRepCommitPreparedTxnData *
 
 	/* read fields */
 	prepare_data->commit_lsn = pq_getmsgint64(in);
-	if (prepare_data->commit_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(prepare_data->commit_lsn))
 		elog(ERROR, "commit_lsn is not set in commit prepared message");
 	prepare_data->end_lsn = pq_getmsgint64(in);
-	if (prepare_data->end_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(prepare_data->end_lsn))
 		elog(ERROR, "end_lsn is not set in commit prepared message");
 	prepare_data->commit_time = pq_getmsgint64(in);
 	prepare_data->xid = pq_getmsgint(in, 4);
@@ -333,10 +333,10 @@ logicalrep_read_rollback_prepared(StringInfo in,
 
 	/* read fields */
 	rollback_data->prepare_end_lsn = pq_getmsgint64(in);
-	if (rollback_data->prepare_end_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(rollback_data->prepare_end_lsn))
 		elog(ERROR, "prepare_end_lsn is not set in rollback prepared message");
 	rollback_data->rollback_end_lsn = pq_getmsgint64(in);
-	if (rollback_data->rollback_end_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(rollback_data->rollback_end_lsn))
 		elog(ERROR, "rollback_end_lsn is not set in rollback prepared message");
 	rollback_data->prepare_time = pq_getmsgint64(in);
 	rollback_data->rollback_time = pq_getmsgint64(in);
diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c
index b57aef9916d..eb6a84554b7 100644
--- a/src/backend/replication/logical/reorderbuffer.c
+++ b/src/backend/replication/logical/reorderbuffer.c
@@ -701,7 +701,7 @@ ReorderBufferTXNByXid(ReorderBuffer *rb, TransactionId xid, bool create,
 	{
 		/* initialize the new entry, if creation was requested */
 		Assert(ent != NULL);
-		Assert(lsn != InvalidXLogRecPtr);
+		Assert(XLogRecPtrIsValid(lsn));
 
 		ent->txn = ReorderBufferAllocTXN(rb);
 		ent->txn->xid = xid;
@@ -849,7 +849,7 @@ ReorderBufferQueueChange(ReorderBuffer *rb, TransactionId xid, XLogRecPtr lsn,
 	change->lsn = lsn;
 	change->txn = txn;
 
-	Assert(InvalidXLogRecPtr != lsn);
+	Assert(XLogRecPtrIsValid(lsn));
 	dlist_push_tail(&txn->changes, &change->node);
 	txn->nentries++;
 	txn->nentries_mem++;
@@ -966,14 +966,14 @@ AssertTXNLsnOrder(ReorderBuffer *rb)
 													iter.cur);
 
 		/* start LSN must be set */
-		Assert(cur_txn->first_lsn != InvalidXLogRecPtr);
+		Assert(XLogRecPtrIsValid(cur_txn->first_lsn));
 
 		/* If there is an end LSN, it must be higher than start LSN */
-		if (cur_txn->end_lsn != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(cur_txn->end_lsn))
 			Assert(cur_txn->first_lsn <= cur_txn->end_lsn);
 
 		/* Current initial LSN must be strictly higher than previous */
-		if (prev_first_lsn != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(prev_first_lsn))
 			Assert(prev_first_lsn < cur_txn->first_lsn);
 
 		/* known-as-subtxn txns must not be listed */
@@ -990,10 +990,10 @@ AssertTXNLsnOrder(ReorderBuffer *rb)
 
 		/* base snapshot (and its LSN) must be set */
 		Assert(cur_txn->base_snapshot != NULL);
-		Assert(cur_txn->base_snapshot_lsn != InvalidXLogRecPtr);
+		Assert(XLogRecPtrIsValid(cur_txn->base_snapshot_lsn));
 
 		/* current LSN must be strictly higher than previous */
-		if (prev_base_snap_lsn != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(prev_base_snap_lsn))
 			Assert(prev_base_snap_lsn < cur_txn->base_snapshot_lsn);
 
 		/* known-as-subtxn txns must not be listed */
@@ -1022,11 +1022,11 @@ AssertChangeLsnOrder(ReorderBufferTXN *txn)
 
 		cur_change = dlist_container(ReorderBufferChange, node, iter.cur);
 
-		Assert(txn->first_lsn != InvalidXLogRecPtr);
-		Assert(cur_change->lsn != InvalidXLogRecPtr);
+		Assert(XLogRecPtrIsValid(txn->first_lsn));
+		Assert(XLogRecPtrIsValid(cur_change->lsn));
 		Assert(txn->first_lsn <= cur_change->lsn);
 
-		if (txn->end_lsn != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(txn->end_lsn))
 			Assert(cur_change->lsn <= txn->end_lsn);
 
 		Assert(prev_lsn <= cur_change->lsn);
@@ -1053,7 +1053,7 @@ ReorderBufferGetOldestTXN(ReorderBuffer *rb)
 	txn = dlist_head_element(ReorderBufferTXN, node, &rb->toplevel_by_lsn);
 
 	Assert(!rbtxn_is_known_subxact(txn));
-	Assert(txn->first_lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(txn->first_lsn));
 	return txn;
 }
 
@@ -2276,7 +2276,7 @@ ReorderBufferProcessTXN(ReorderBuffer *rb, ReorderBufferTXN *txn,
 			 * We can't call start stream callback before processing first
 			 * change.
 			 */
-			if (prev_lsn == InvalidXLogRecPtr)
+			if (!XLogRecPtrIsValid(prev_lsn))
 			{
 				if (streaming)
 				{
@@ -2291,7 +2291,7 @@ ReorderBufferProcessTXN(ReorderBuffer *rb, ReorderBufferTXN *txn,
 			 * subtransactions. The changes may have the same LSN due to
 			 * MULTI_INSERT xlog records.
 			 */
-			Assert(prev_lsn == InvalidXLogRecPtr || prev_lsn <= change->lsn);
+			Assert(!XLogRecPtrIsValid(prev_lsn) || prev_lsn <= change->lsn);
 
 			prev_lsn = change->lsn;
 
@@ -2975,7 +2975,7 @@ ReorderBufferPrepare(ReorderBuffer *rb, TransactionId xid,
 	 * have been updated in it by now.
 	 */
 	Assert((txn->txn_flags & RBTXN_PREPARE_STATUS_MASK) == RBTXN_IS_PREPARED);
-	Assert(txn->final_lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(txn->final_lsn));
 
 	txn->gid = pstrdup(gid);
 
@@ -3041,7 +3041,7 @@ ReorderBufferFinishPrepared(ReorderBuffer *rb, TransactionId xid,
 		 */
 		Assert((txn->txn_flags & RBTXN_PREPARE_STATUS_MASK) ==
 			   (RBTXN_IS_PREPARED | RBTXN_SKIPPED_PREPARE));
-		Assert(txn->final_lsn != InvalidXLogRecPtr);
+		Assert(XLogRecPtrIsValid(txn->final_lsn));
 
 		/*
 		 * By this time the txn has the prepare record information and it is
@@ -4552,8 +4552,8 @@ ReorderBufferRestoreChanges(ReorderBuffer *rb, ReorderBufferTXN *txn,
 	dlist_mutable_iter cleanup_iter;
 	File	   *fd = &file->vfd;
 
-	Assert(txn->first_lsn != InvalidXLogRecPtr);
-	Assert(txn->final_lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(txn->first_lsn));
+	Assert(XLogRecPtrIsValid(txn->final_lsn));
 
 	/* free current entries, so we have memory for more */
 	dlist_foreach_modify(cleanup_iter, &txn->changes)
@@ -4860,8 +4860,8 @@ ReorderBufferRestoreCleanup(ReorderBuffer *rb, ReorderBufferTXN *txn)
 	XLogSegNo	cur;
 	XLogSegNo	last;
 
-	Assert(txn->first_lsn != InvalidXLogRecPtr);
-	Assert(txn->final_lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(txn->first_lsn));
+	Assert(XLogRecPtrIsValid(txn->final_lsn));
 
 	XLByteToSeg(txn->first_lsn, first, wal_segment_size);
 	XLByteToSeg(txn->final_lsn, last, wal_segment_size);
diff --git a/src/backend/replication/logical/snapbuild.c b/src/backend/replication/logical/snapbuild.c
index 98ddee20929..6e18baa33cb 100644
--- a/src/backend/replication/logical/snapbuild.c
+++ b/src/backend/replication/logical/snapbuild.c
@@ -1210,7 +1210,7 @@ SnapBuildProcessRunningXacts(SnapBuild *builder, XLogRecPtr lsn, xl_running_xact
 	 * oldest ongoing txn might have started when we didn't yet serialize
 	 * anything because we hadn't reached a consistent state yet.
 	 */
-	if (txn != NULL && txn->restart_decoding_lsn != InvalidXLogRecPtr)
+	if (txn != NULL && XLogRecPtrIsValid(txn->restart_decoding_lsn))
 		LogicalIncreaseRestartDecodingForSlot(lsn, txn->restart_decoding_lsn);
 
 	/*
@@ -1218,8 +1218,8 @@ SnapBuildProcessRunningXacts(SnapBuild *builder, XLogRecPtr lsn, xl_running_xact
 	 * we have one.
 	 */
 	else if (txn == NULL &&
-			 builder->reorder->current_restart_decoding_lsn != InvalidXLogRecPtr &&
-			 builder->last_serialized_snapshot != InvalidXLogRecPtr)
+			 XLogRecPtrIsValid(builder->reorder->current_restart_decoding_lsn) &&
+			 XLogRecPtrIsValid(builder->last_serialized_snapshot))
 		LogicalIncreaseRestartDecodingForSlot(lsn,
 											  builder->last_serialized_snapshot);
 }
@@ -1293,7 +1293,7 @@ SnapBuildFindSnapshot(SnapBuild *builder, XLogRecPtr lsn, xl_running_xacts *runn
 	 */
 	if (running->oldestRunningXid == running->nextXid)
 	{
-		if (builder->start_decoding_at == InvalidXLogRecPtr ||
+		if (!XLogRecPtrIsValid(builder->start_decoding_at) ||
 			builder->start_decoding_at <= lsn)
 			/* can decode everything after this */
 			builder->start_decoding_at = lsn + 1;
@@ -1509,8 +1509,8 @@ SnapBuildSerialize(SnapBuild *builder, XLogRecPtr lsn)
 	struct stat stat_buf;
 	Size		sz;
 
-	Assert(lsn != InvalidXLogRecPtr);
-	Assert(builder->last_serialized_snapshot == InvalidXLogRecPtr ||
+	Assert(XLogRecPtrIsValid(lsn));
+	Assert(!XLogRecPtrIsValid(builder->last_serialized_snapshot) ||
 		   builder->last_serialized_snapshot <= lsn);
 
 	/*
@@ -2029,7 +2029,7 @@ CheckPointSnapBuild(void)
 		lsn = ((uint64) hi) << 32 | lo;
 
 		/* check whether we still need it */
-		if (lsn < cutoff || cutoff == InvalidXLogRecPtr)
+		if (lsn < cutoff || !XLogRecPtrIsValid(cutoff))
 		{
 			elog(DEBUG1, "removing snapbuild snapshot %s", path);
 
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index 0cb93dc90f2..1ec1e997b27 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -1270,15 +1270,15 @@ ReplicationSlotsComputeRequiredLSN(void)
 		 */
 		if (persistency == RS_PERSISTENT)
 		{
-			if (last_saved_restart_lsn != InvalidXLogRecPtr &&
+			if (XLogRecPtrIsValid(last_saved_restart_lsn) &&
 				restart_lsn > last_saved_restart_lsn)
 			{
 				restart_lsn = last_saved_restart_lsn;
 			}
 		}
 
-		if (restart_lsn != InvalidXLogRecPtr &&
-			(min_required == InvalidXLogRecPtr ||
+		if (XLogRecPtrIsValid(restart_lsn) &&
+			(!XLogRecPtrIsValid(min_required) ||
 			 restart_lsn < min_required))
 			min_required = restart_lsn;
 	}
@@ -1350,17 +1350,17 @@ ReplicationSlotsComputeLogicalRestartLSN(void)
 		 */
 		if (persistency == RS_PERSISTENT)
 		{
-			if (last_saved_restart_lsn != InvalidXLogRecPtr &&
+			if (XLogRecPtrIsValid(last_saved_restart_lsn) &&
 				restart_lsn > last_saved_restart_lsn)
 			{
 				restart_lsn = last_saved_restart_lsn;
 			}
 		}
 
-		if (restart_lsn == InvalidXLogRecPtr)
+		if (!XLogRecPtrIsValid(restart_lsn))
 			continue;
 
-		if (result == InvalidXLogRecPtr ||
+		if (!XLogRecPtrIsValid(result) ||
 			restart_lsn < result)
 			result = restart_lsn;
 	}
@@ -1573,8 +1573,8 @@ ReplicationSlotReserveWal(void)
 	ReplicationSlot *slot = MyReplicationSlot;
 
 	Assert(slot != NULL);
-	Assert(slot->data.restart_lsn == InvalidXLogRecPtr);
-	Assert(slot->last_saved_restart_lsn == InvalidXLogRecPtr);
+	Assert(!XLogRecPtrIsValid(slot->data.restart_lsn));
+	Assert(!XLogRecPtrIsValid(slot->last_saved_restart_lsn));
 
 	/*
 	 * The replication slot mechanism is used to prevent removal of required
@@ -1754,7 +1754,7 @@ DetermineSlotInvalidationCause(uint32 possible_causes, ReplicationSlot *s,
 	{
 		XLogRecPtr	restart_lsn = s->data.restart_lsn;
 
-		if (restart_lsn != InvalidXLogRecPtr &&
+		if (XLogRecPtrIsValid(restart_lsn) &&
 			restart_lsn < oldestLSN)
 			return RS_INVAL_WAL_REMOVED;
 	}
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 5aecd5c6a50..0478fc9c977 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -308,12 +308,12 @@ pg_get_replication_slots(PG_FUNCTION_ARGS)
 		else
 			nulls[i++] = true;
 
-		if (slot_contents.data.restart_lsn != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(slot_contents.data.restart_lsn))
 			values[i++] = LSNGetDatum(slot_contents.data.restart_lsn);
 		else
 			nulls[i++] = true;
 
-		if (slot_contents.data.confirmed_flush != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(slot_contents.data.confirmed_flush))
 			values[i++] = LSNGetDatum(slot_contents.data.confirmed_flush);
 		else
 			nulls[i++] = true;
@@ -467,7 +467,7 @@ pg_physical_replication_slot_advance(XLogRecPtr moveto)
 	XLogRecPtr	startlsn = MyReplicationSlot->data.restart_lsn;
 	XLogRecPtr	retlsn = startlsn;
 
-	Assert(moveto != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(moveto));
 
 	if (startlsn < moveto)
 	{
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index b6dfb230d0d..4a678e60b74 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -2397,7 +2397,7 @@ PhysicalConfirmReceivedLocation(XLogRecPtr lsn)
 	bool		changed = false;
 	ReplicationSlot *slot = MyReplicationSlot;
 
-	Assert(lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(lsn));
 	SpinLockAcquire(&slot->mutex);
 	if (slot->data.restart_lsn != lsn)
 	{
@@ -2519,7 +2519,7 @@ ProcessStandbyReplyMessage(void)
 	/*
 	 * Advance our local xmin horizon when the client confirmed a flush.
 	 */
-	if (MyReplicationSlot && flushPtr != InvalidXLogRecPtr)
+	if (MyReplicationSlot && XLogRecPtrIsValid(flushPtr))
 	{
 		if (SlotIsLogical(MyReplicationSlot))
 			LogicalConfirmReceivedLocation(flushPtr);
@@ -3536,7 +3536,7 @@ XLogSendLogical(void)
 	 * If first time through in this session, initialize flushPtr.  Otherwise,
 	 * we only need to update flushPtr if EndRecPtr is past it.
 	 */
-	if (flushPtr == InvalidXLogRecPtr ||
+	if (!XLogRecPtrIsValid(flushPtr) ||
 		logical_decoding_ctx->reader->EndRecPtr >= flushPtr)
 	{
 		/*
diff --git a/src/bin/pg_basebackup/pg_receivewal.c b/src/bin/pg_basebackup/pg_receivewal.c
index 3e6f4a7fc48..46e553dce4b 100644
--- a/src/bin/pg_basebackup/pg_receivewal.c
+++ b/src/bin/pg_basebackup/pg_receivewal.c
@@ -535,7 +535,7 @@ StreamLog(void)
 	 * Figure out where to start streaming.  First scan the local directory.
 	 */
 	stream.startpos = FindStreamingStart(&stream.timeline);
-	if (stream.startpos == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(stream.startpos))
 	{
 		/*
 		 * Try to get the starting point from the slot if any.  This is
@@ -556,14 +556,14 @@ StreamLog(void)
 		 * If it the starting point is still not known, use the current WAL
 		 * flush value as last resort.
 		 */
-		if (stream.startpos == InvalidXLogRecPtr)
+		if (!XLogRecPtrIsValid(stream.startpos))
 		{
 			stream.startpos = serverpos;
 			stream.timeline = servertli;
 		}
 	}
 
-	Assert(stream.startpos != InvalidXLogRecPtr &&
+	Assert(XLogRecPtrIsValid(stream.startpos) &&
 		   stream.timeline != 0);
 
 	/*
diff --git a/src/bin/pg_basebackup/pg_recvlogical.c b/src/bin/pg_basebackup/pg_recvlogical.c
index 6739784a993..14ad1504678 100644
--- a/src/bin/pg_basebackup/pg_recvlogical.c
+++ b/src/bin/pg_basebackup/pg_recvlogical.c
@@ -482,7 +482,7 @@ StreamLogicalLog(void)
 			}
 			replyRequested = copybuf[pos];
 
-			if (endpos != InvalidXLogRecPtr && walEnd >= endpos)
+			if (XLogRecPtrIsValid(endpos) && walEnd >= endpos)
 			{
 				/*
 				 * If there's nothing to read on the socket until a keepalive
@@ -535,7 +535,7 @@ StreamLogicalLog(void)
 		/* Extract WAL location for this block */
 		cur_record_lsn = fe_recvint64(&copybuf[1]);
 
-		if (endpos != InvalidXLogRecPtr && cur_record_lsn > endpos)
+		if (XLogRecPtrIsValid(endpos) && cur_record_lsn > endpos)
 		{
 			/*
 			 * We've read past our endpoint, so prepare to go away being
@@ -583,7 +583,7 @@ StreamLogicalLog(void)
 			goto error;
 		}
 
-		if (endpos != InvalidXLogRecPtr && cur_record_lsn == endpos)
+		if (XLogRecPtrIsValid(endpos) && cur_record_lsn == endpos)
 		{
 			/* endpos was exactly the record we just processed, we're done */
 			if (!flushAndSendFeedback(conn, &now))
@@ -913,14 +913,14 @@ main(int argc, char **argv)
 		exit(1);
 	}
 
-	if (startpos != InvalidXLogRecPtr && (do_create_slot || do_drop_slot))
+	if (XLogRecPtrIsValid(startpos) && (do_create_slot || do_drop_slot))
 	{
 		pg_log_error("cannot use --create-slot or --drop-slot together with --startpos");
 		pg_log_error_hint("Try \"%s --help\" for more information.", progname);
 		exit(1);
 	}
 
-	if (endpos != InvalidXLogRecPtr && !do_start_slot)
+	if (XLogRecPtrIsValid(endpos) && !do_start_slot)
 	{
 		pg_log_error("--endpos may only be specified with --start");
 		pg_log_error_hint("Try \"%s --help\" for more information.", progname);
diff --git a/src/bin/pg_waldump/pg_waldump.c b/src/bin/pg_waldump/pg_waldump.c
index 19cf5461eac..c6d6ba79e44 100644
--- a/src/bin/pg_waldump/pg_waldump.c
+++ b/src/bin/pg_waldump/pg_waldump.c
@@ -393,7 +393,7 @@ WALDumpReadPage(XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen,
 	int			count = XLOG_BLCKSZ;
 	WALReadError errinfo;
 
-	if (private->endptr != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(private->endptr))
 	{
 		if (targetPagePtr + XLOG_BLCKSZ <= private->endptr)
 			count = XLOG_BLCKSZ;
@@ -1213,7 +1213,7 @@ main(int argc, char **argv)
 	/* first find a valid recptr to start from */
 	first_record = XLogFindNextRecord(xlogreader_state, private.startptr);
 
-	if (first_record == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(first_record))
 		pg_fatal("could not find a valid record after %X/%08X",
 				 LSN_FORMAT_ARGS(private.startptr));
 
diff --git a/src/include/access/xlogdefs.h b/src/include/access/xlogdefs.h
index 2589a21083b..06fcfeeb9d0 100644
--- a/src/include/access/xlogdefs.h
+++ b/src/include/access/xlogdefs.h
@@ -41,7 +41,7 @@ PG_DEPRECATED("use XLogRecPtrIsValid() instead")
 static inline bool
 XLogRecPtrIsInvalid(XLogRecPtr ptr)
 {
-	return ptr == InvalidXLogRecPtr;
+	return !XLogRecPtrIsValid(ptr);
 }
 
 /*
-- 
2.34.1

v4-0004-Replace-literal-0-comparisons-on-XLogRecPtr-with-.patchtext/x-diff; charset=us-asciiDownload
From 05ed7733ec60a91660df28794b342ba9ca3929ce Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Wed, 29 Oct 2025 18:46:28 +0000
Subject: [PATCH v4 4/4] Replace literal 0 comparisons on XLogRecPtr with
 XLogRecPtrIsValid()

This commit ensures the XLogRecPtrIsValid() macro is used instead of direct
literal 0 comparisons on XLogRecPtr.
---
 src/backend/access/transam/xlogfuncs.c     | 4 ++--
 src/backend/replication/walreceiverfuncs.c | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)
  42.3% src/backend/access/transam/
  57.6% src/backend/replication/

diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index 8c3090165f0..3e45fce43ed 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -341,7 +341,7 @@ pg_last_wal_receive_lsn(PG_FUNCTION_ARGS)
 
 	recptr = GetWalRcvFlushRecPtr(NULL, NULL);
 
-	if (recptr == 0)
+	if (!XLogRecPtrIsValid(recptr))
 		PG_RETURN_NULL();
 
 	PG_RETURN_LSN(recptr);
@@ -360,7 +360,7 @@ pg_last_wal_replay_lsn(PG_FUNCTION_ARGS)
 
 	recptr = GetXLogReplayRecPtr(NULL);
 
-	if (recptr == 0)
+	if (!XLogRecPtrIsValid(recptr))
 		PG_RETURN_NULL();
 
 	PG_RETURN_LSN(recptr);
diff --git a/src/backend/replication/walreceiverfuncs.c b/src/backend/replication/walreceiverfuncs.c
index 8de2886ff0b..f447ded2d07 100644
--- a/src/backend/replication/walreceiverfuncs.c
+++ b/src/backend/replication/walreceiverfuncs.c
@@ -301,7 +301,7 @@ RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, const char *conninfo,
 	 * If this is the first startup of walreceiver (on this timeline),
 	 * initialize flushedUpto and latestChunkStart to the starting point.
 	 */
-	if (walrcv->receiveStart == 0 || walrcv->receivedTLI != tli)
+	if (!XLogRecPtrIsValid(walrcv->receiveStart) || walrcv->receivedTLI != tli)
 	{
 		walrcv->flushedUpto = recptr;
 		walrcv->receivedTLI = tli;
-- 
2.34.1

#17Bertrand Drouvot
bertranddrouvot.pg@gmail.com
In reply to: Bertrand Drouvot (#16)
4 attachment(s)
Re: Consistently use the XLogRecPtrIsInvalid() macro

Hi,

On Mon, Nov 03, 2025 at 07:47:28AM +0000, Bertrand Drouvot wrote:

I think the way it is done in the attached makes sense, it:

- introduces PG_DEPRECATED()
- provides a use case on how to use it (i.e using a version that is currently
in the future)
- ensures that XLogRecPtrIsInvalid() deprecation is "enforced" as of version 24
- ensures that not using XLogRecPtrIsInvalid() is documented (so that it should
not be used anymore, at least in core, even waiting for version 24)

Attached a rebase due to 6d0eba66275 and 447aae13b03.

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

Attachments:

v5-0001-Introduce-XLogRecPtrIsValid-and-replace-XLogRecPt.patchtext/x-diff; charset=us-asciiDownload
From b300dfe9f8525b28d3ff0fe397315b3c6a0de379 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Wed, 29 Oct 2025 10:34:03 +0000
Subject: [PATCH v5 1/4] Introduce XLogRecPtrIsValid() and replace
 XLogRecPtrIsInvalid() calls

XLogRecPtrIsInvalid() is inconsistent with the affirmative form of other
*IsValid() macros and leads to awkward double negative.

This commit introduces XLogRecPtrIsValid() and replace all the
XLogRecPtrIsInvalid() calls.

It also adds a comment mentioning that new code should use XLogRecPtrIsValid()
instead of XLogRecPtrIsInvalid() and that XLogRecPtrIsInvalid() could be
deprecated in the future.
---
 contrib/pg_walinspect/pg_walinspect.c         |  4 +--
 src/backend/access/gist/gist.c                |  4 +--
 src/backend/access/gist/gistget.c             |  4 +--
 src/backend/access/gist/gistutil.c            |  2 +-
 src/backend/access/heap/visibilitymap.c       |  4 +--
 src/backend/access/transam/clog.c             |  5 ++--
 src/backend/access/transam/slru.c             |  2 +-
 src/backend/access/transam/timeline.c         |  4 +--
 src/backend/access/transam/twophase.c         |  4 +--
 src/backend/access/transam/xlog.c             | 30 +++++++++----------
 src/backend/access/transam/xlogbackup.c       |  4 +--
 src/backend/access/transam/xlogreader.c       |  6 ++--
 src/backend/access/transam/xlogrecovery.c     | 12 ++++----
 src/backend/access/transam/xlogwait.c         |  2 +-
 src/backend/backup/backup_manifest.c          |  4 +--
 src/backend/backup/basebackup_incremental.c   |  2 +-
 src/backend/backup/walsummary.c               |  8 ++---
 src/backend/commands/subscriptioncmds.c       |  6 ++--
 src/backend/postmaster/walsummarizer.c        | 18 +++++------
 .../replication/logical/applyparallelworker.c |  4 +--
 src/backend/replication/logical/launcher.c    |  4 +--
 src/backend/replication/logical/logical.c     |  2 +-
 .../replication/logical/logicalfuncs.c        |  2 +-
 src/backend/replication/logical/slotsync.c    |  6 ++--
 src/backend/replication/logical/worker.c      | 16 +++++-----
 src/backend/replication/slot.c                | 10 +++----
 src/backend/replication/slotfuncs.c           | 16 +++++-----
 src/backend/replication/syncrep.c             | 10 +++----
 src/backend/replication/walreceiver.c         |  8 ++---
 src/backend/replication/walsender.c           | 22 +++++++-------
 src/backend/storage/buffer/bufmgr.c           |  2 +-
 src/bin/pg_basebackup/pg_receivewal.c         |  2 +-
 src/bin/pg_basebackup/pg_recvlogical.c        |  2 +-
 src/bin/pg_rewind/pg_rewind.c                 |  4 +--
 src/bin/pg_waldump/pg_waldump.c               | 10 +++----
 src/include/access/xlogdefs.h                 | 10 ++++++-
 36 files changed, 132 insertions(+), 123 deletions(-)
   4.2% src/backend/access/gist/
  27.6% src/backend/access/transam/
   6.4% src/backend/backup/
   7.5% src/backend/postmaster/
  13.8% src/backend/replication/logical/
  25.9% src/backend/replication/
   4.0% src/backend/
   3.7% src/bin/pg_waldump/
   5.2% src/

diff --git a/contrib/pg_walinspect/pg_walinspect.c b/contrib/pg_walinspect/pg_walinspect.c
index 501cea8fc1a..3c5e4a856a7 100644
--- a/contrib/pg_walinspect/pg_walinspect.c
+++ b/contrib/pg_walinspect/pg_walinspect.c
@@ -83,7 +83,7 @@ GetCurrentLSN(void)
 	else
 		curr_lsn = GetXLogReplayRecPtr(NULL);
 
-	Assert(!XLogRecPtrIsInvalid(curr_lsn));
+	Assert(XLogRecPtrIsValid(curr_lsn));
 
 	return curr_lsn;
 }
@@ -127,7 +127,7 @@ InitXLogReaderState(XLogRecPtr lsn)
 	/* first find a valid recptr to start from */
 	first_valid_record = XLogFindNextRecord(xlogreader, lsn);
 
-	if (XLogRecPtrIsInvalid(first_valid_record))
+	if (!XLogRecPtrIsValid(first_valid_record))
 		ereport(ERROR,
 				errmsg("could not find a valid record after %X/%08X",
 					   LSN_FORMAT_ARGS(lsn)));
diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c
index 5213cd71e97..3fb1a1285c5 100644
--- a/src/backend/access/gist/gist.c
+++ b/src/backend/access/gist/gist.c
@@ -682,7 +682,7 @@ gistdoinsert(Relation r, IndexTuple itup, Size freespace,
 			state.stack = stack = stack->parent;
 		}
 
-		if (XLogRecPtrIsInvalid(stack->lsn))
+		if (!XLogRecPtrIsValid(stack->lsn))
 			stack->buffer = ReadBuffer(state.r, stack->blkno);
 
 		/*
@@ -698,7 +698,7 @@ gistdoinsert(Relation r, IndexTuple itup, Size freespace,
 		stack->page = BufferGetPage(stack->buffer);
 		stack->lsn = xlocked ?
 			PageGetLSN(stack->page) : BufferGetLSNAtomic(stack->buffer);
-		Assert(!RelationNeedsWAL(state.r) || !XLogRecPtrIsInvalid(stack->lsn));
+		Assert(!RelationNeedsWAL(state.r) || XLogRecPtrIsValid(stack->lsn));
 
 		/*
 		 * If this page was split but the downlink was never inserted to the
diff --git a/src/backend/access/gist/gistget.c b/src/backend/access/gist/gistget.c
index 387d9972345..9ba45acfff3 100644
--- a/src/backend/access/gist/gistget.c
+++ b/src/backend/access/gist/gistget.c
@@ -46,7 +46,7 @@ gistkillitems(IndexScanDesc scan)
 	bool		killedsomething = false;
 
 	Assert(so->curBlkno != InvalidBlockNumber);
-	Assert(!XLogRecPtrIsInvalid(so->curPageLSN));
+	Assert(XLogRecPtrIsValid(so->curPageLSN));
 	Assert(so->killedItems != NULL);
 
 	buffer = ReadBuffer(scan->indexRelation, so->curBlkno);
@@ -353,7 +353,7 @@ gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem,
 	 * parentlsn < nsn), or if the system crashed after a page split but
 	 * before the downlink was inserted into the parent.
 	 */
-	if (!XLogRecPtrIsInvalid(pageItem->data.parentlsn) &&
+	if (XLogRecPtrIsValid(pageItem->data.parentlsn) &&
 		(GistFollowRight(page) ||
 		 pageItem->data.parentlsn < GistPageGetNSN(page)) &&
 		opaque->rightlink != InvalidBlockNumber /* sanity check */ )
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index 98b79608341..75272827837 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -1040,7 +1040,7 @@ gistGetFakeLSN(Relation rel)
 		Assert(!RelationNeedsWAL(rel));
 
 		/* No need for an actual record if we already have a distinct LSN */
-		if (!XLogRecPtrIsInvalid(lastlsn) && lastlsn == currlsn)
+		if (XLogRecPtrIsValid(lastlsn) && lastlsn == currlsn)
 			currlsn = gistXLogAssignLSN();
 
 		lastlsn = currlsn;
diff --git a/src/backend/access/heap/visibilitymap.c b/src/backend/access/heap/visibilitymap.c
index 2f5e61e2392..d14588e92ae 100644
--- a/src/backend/access/heap/visibilitymap.c
+++ b/src/backend/access/heap/visibilitymap.c
@@ -260,7 +260,7 @@ visibilitymap_set(Relation rel, BlockNumber heapBlk, Buffer heapBuf,
 		 flags, RelationGetRelationName(rel), heapBlk);
 #endif
 
-	Assert(InRecovery || XLogRecPtrIsInvalid(recptr));
+	Assert(InRecovery || !XLogRecPtrIsValid(recptr));
 	Assert(InRecovery || PageIsAllVisible(BufferGetPage(heapBuf)));
 	Assert((flags & VISIBILITYMAP_VALID_BITS) == flags);
 
@@ -292,7 +292,7 @@ visibilitymap_set(Relation rel, BlockNumber heapBlk, Buffer heapBuf,
 
 		if (RelationNeedsWAL(rel))
 		{
-			if (XLogRecPtrIsInvalid(recptr))
+			if (!XLogRecPtrIsValid(recptr))
 			{
 				Assert(!InRecovery);
 				recptr = log_heap_visible(rel, heapBuf, vmBuf, cutoff_xid, flags);
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index e80fbe109cf..ea43b432daf 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -381,7 +381,8 @@ TransactionIdSetPageStatusInternal(TransactionId xid, int nsubxids,
 	 * write-busy, since we don't care if the update reaches disk sooner than
 	 * we think.
 	 */
-	slotno = SimpleLruReadPage(XactCtl, pageno, XLogRecPtrIsInvalid(lsn), xid);
+	slotno = SimpleLruReadPage(XactCtl, pageno, !XLogRecPtrIsValid(lsn),
+							   xid);
 
 	/*
 	 * Set the main transaction id, if any.
@@ -705,7 +706,7 @@ TransactionIdSetStatusBit(TransactionId xid, XidStatus status, XLogRecPtr lsn, i
 	 * recovery. After recovery completes the next clog change will set the
 	 * LSN correctly.
 	 */
-	if (!XLogRecPtrIsInvalid(lsn))
+	if (XLogRecPtrIsValid(lsn))
 	{
 		int			lsnindex = GetLSNIndex(slotno, xid);
 
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index 5d3fcd62c94..77676d6d035 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -937,7 +937,7 @@ SlruPhysicalWritePage(SlruCtl ctl, int64 pageno, int slotno, SlruWriteAll fdata)
 				max_lsn = this_lsn;
 		}
 
-		if (!XLogRecPtrIsInvalid(max_lsn))
+		if (XLogRecPtrIsValid(max_lsn))
 		{
 			/*
 			 * As noted above, elog(ERROR) is not acceptable here, so if
diff --git a/src/backend/access/transam/timeline.c b/src/backend/access/transam/timeline.c
index 186eb91f609..ec3e323ec0c 100644
--- a/src/backend/access/transam/timeline.c
+++ b/src/backend/access/transam/timeline.c
@@ -549,8 +549,8 @@ tliOfPointInHistory(XLogRecPtr ptr, List *history)
 	{
 		TimeLineHistoryEntry *tle = (TimeLineHistoryEntry *) lfirst(cell);
 
-		if ((XLogRecPtrIsInvalid(tle->begin) || tle->begin <= ptr) &&
-			(XLogRecPtrIsInvalid(tle->end) || ptr < tle->end))
+		if ((!XLogRecPtrIsValid(tle->begin) || tle->begin <= ptr) &&
+			(!XLogRecPtrIsValid(tle->end) || ptr < tle->end))
 		{
 			/* found it */
 			return tle->tli;
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 33369fbe23a..8a92b292e56 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -2547,7 +2547,7 @@ PrepareRedoAdd(FullTransactionId fxid, char *buf,
 	 * the record is added to TwoPhaseState and it should have no
 	 * corresponding file in pg_twophase.
 	 */
-	if (!XLogRecPtrIsInvalid(start_lsn))
+	if (XLogRecPtrIsValid(start_lsn))
 	{
 		char		path[MAXPGPATH];
 
@@ -2587,7 +2587,7 @@ PrepareRedoAdd(FullTransactionId fxid, char *buf,
 	gxact->owner = hdr->owner;
 	gxact->locking_backend = INVALID_PROC_NUMBER;
 	gxact->valid = false;
-	gxact->ondisk = XLogRecPtrIsInvalid(start_lsn);
+	gxact->ondisk = !XLogRecPtrIsValid(start_lsn);
 	gxact->inredo = true;		/* yes, added in redo */
 	strcpy(gxact->gid, gid);
 
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 7c959051e11..0564482cda8 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -1762,7 +1762,7 @@ WALReadFromBuffers(char *dstbuf, XLogRecPtr startptr, Size count,
 	if (RecoveryInProgress() || tli != GetWALInsertionTimeLine())
 		return 0;
 
-	Assert(!XLogRecPtrIsInvalid(startptr));
+	Assert(XLogRecPtrIsValid(startptr));
 
 	/*
 	 * Caller should ensure that the requested data has been inserted into WAL
@@ -2717,7 +2717,7 @@ UpdateMinRecoveryPoint(XLogRecPtr lsn, bool force)
 	 * available is replayed in this case.  This also saves from extra locks
 	 * taken on the control file from the startup process.
 	 */
-	if (XLogRecPtrIsInvalid(LocalMinRecoveryPoint) && InRecovery)
+	if (!XLogRecPtrIsValid(LocalMinRecoveryPoint) && InRecovery)
 	{
 		updateMinRecoveryPoint = false;
 		return;
@@ -2729,7 +2729,7 @@ UpdateMinRecoveryPoint(XLogRecPtr lsn, bool force)
 	LocalMinRecoveryPoint = ControlFile->minRecoveryPoint;
 	LocalMinRecoveryPointTLI = ControlFile->minRecoveryPointTLI;
 
-	if (XLogRecPtrIsInvalid(LocalMinRecoveryPoint))
+	if (!XLogRecPtrIsValid(LocalMinRecoveryPoint))
 		updateMinRecoveryPoint = false;
 	else if (force || LocalMinRecoveryPoint < lsn)
 	{
@@ -3149,7 +3149,7 @@ XLogNeedsFlush(XLogRecPtr record)
 		 * which cannot update its local copy of minRecoveryPoint as long as
 		 * it has not replayed all WAL available when doing crash recovery.
 		 */
-		if (XLogRecPtrIsInvalid(LocalMinRecoveryPoint) && InRecovery)
+		if (!XLogRecPtrIsValid(LocalMinRecoveryPoint) && InRecovery)
 		{
 			updateMinRecoveryPoint = false;
 			return false;
@@ -3170,7 +3170,7 @@ XLogNeedsFlush(XLogRecPtr record)
 		 * process doing crash recovery, which should not update the control
 		 * file value if crash recovery is still running.
 		 */
-		if (XLogRecPtrIsInvalid(LocalMinRecoveryPoint))
+		if (!XLogRecPtrIsValid(LocalMinRecoveryPoint))
 			updateMinRecoveryPoint = false;
 
 		/* check again */
@@ -5935,7 +5935,7 @@ StartupXLOG(void)
 	 */
 	if (InRecovery &&
 		(EndOfLog < LocalMinRecoveryPoint ||
-		 !XLogRecPtrIsInvalid(ControlFile->backupStartPoint)))
+		 XLogRecPtrIsValid(ControlFile->backupStartPoint)))
 	{
 		/*
 		 * Ran off end of WAL before reaching end-of-backup WAL record, or
@@ -5945,7 +5945,7 @@ StartupXLOG(void)
 		 */
 		if (ArchiveRecoveryRequested || ControlFile->backupEndRequired)
 		{
-			if (!XLogRecPtrIsInvalid(ControlFile->backupStartPoint) || ControlFile->backupEndRequired)
+			if (XLogRecPtrIsValid(ControlFile->backupStartPoint) || ControlFile->backupEndRequired)
 				ereport(FATAL,
 						(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 						 errmsg("WAL ends before end of online backup"),
@@ -6047,7 +6047,7 @@ StartupXLOG(void)
 	 * (It's critical to first write an OVERWRITE_CONTRECORD message, which
 	 * we'll do as soon as we're open for writing new WAL.)
 	 */
-	if (!XLogRecPtrIsInvalid(missingContrecPtr))
+	if (XLogRecPtrIsValid(missingContrecPtr))
 	{
 		/*
 		 * We should only have a missingContrecPtr if we're not switching to a
@@ -6057,7 +6057,7 @@ StartupXLOG(void)
 		 * disregard.
 		 */
 		Assert(newTLI == endOfRecoveryInfo->lastRecTLI);
-		Assert(!XLogRecPtrIsInvalid(abortedRecPtr));
+		Assert(XLogRecPtrIsValid(abortedRecPtr));
 		EndOfLog = missingContrecPtr;
 	}
 
@@ -6161,9 +6161,9 @@ StartupXLOG(void)
 	LocalSetXLogInsertAllowed();
 
 	/* If necessary, write overwrite-contrecord before doing anything else */
-	if (!XLogRecPtrIsInvalid(abortedRecPtr))
+	if (XLogRecPtrIsValid(abortedRecPtr))
 	{
-		Assert(!XLogRecPtrIsInvalid(missingContrecPtr));
+		Assert(XLogRecPtrIsValid(missingContrecPtr));
 		CreateOverwriteContrecordRecord(abortedRecPtr, missingContrecPtr, newTLI);
 	}
 
@@ -7693,7 +7693,7 @@ CreateRestartPoint(int flags)
 	 * restartpoint. It's assumed that flushing the buffers will do that as a
 	 * side-effect.
 	 */
-	if (XLogRecPtrIsInvalid(lastCheckPointRecPtr) ||
+	if (!XLogRecPtrIsValid(lastCheckPointRecPtr) ||
 		lastCheckPoint.redo <= ControlFile->checkPointCopy.redo)
 	{
 		ereport(DEBUG2,
@@ -7936,7 +7936,7 @@ GetWALAvailability(XLogRecPtr targetLSN)
 	/*
 	 * slot does not reserve WAL. Either deactivated, or has never been active
 	 */
-	if (XLogRecPtrIsInvalid(targetLSN))
+	if (!XLogRecPtrIsValid(targetLSN))
 		return WALAVAIL_INVALID_LSN;
 
 	/*
@@ -8352,8 +8352,8 @@ xlog_redo(XLogReaderState *record)
 		 * never arrive.
 		 */
 		if (ArchiveRecoveryRequested &&
-			!XLogRecPtrIsInvalid(ControlFile->backupStartPoint) &&
-			XLogRecPtrIsInvalid(ControlFile->backupEndPoint))
+			XLogRecPtrIsValid(ControlFile->backupStartPoint) &&
+			!XLogRecPtrIsValid(ControlFile->backupEndPoint))
 			ereport(PANIC,
 					(errmsg("online backup was canceled, recovery cannot continue")));
 
diff --git a/src/backend/access/transam/xlogbackup.c b/src/backend/access/transam/xlogbackup.c
index 8a8a2a7b326..7e48aa43901 100644
--- a/src/backend/access/transam/xlogbackup.c
+++ b/src/backend/access/transam/xlogbackup.c
@@ -79,8 +79,8 @@ build_backup_content(BackupState *state, bool ishistoryfile)
 	}
 
 	/* either both istartpoint and istarttli should be set, or neither */
-	Assert(XLogRecPtrIsInvalid(state->istartpoint) == (state->istarttli == 0));
-	if (!XLogRecPtrIsInvalid(state->istartpoint))
+	Assert(!XLogRecPtrIsValid(state->istartpoint) == (state->istarttli == 0));
+	if (XLogRecPtrIsValid(state->istartpoint))
 	{
 		appendStringInfo(&result, "INCREMENTAL FROM LSN: %X/%08X\n",
 						 LSN_FORMAT_ARGS(state->istartpoint));
diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index dcc8d4f9c1b..aad16127e60 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -231,7 +231,7 @@ WALOpenSegmentInit(WALOpenSegment *seg, WALSegmentContext *segcxt,
 void
 XLogBeginRead(XLogReaderState *state, XLogRecPtr RecPtr)
 {
-	Assert(!XLogRecPtrIsInvalid(RecPtr));
+	Assert(XLogRecPtrIsValid(RecPtr));
 
 	ResetDecoder(state);
 
@@ -343,7 +343,7 @@ XLogNextRecord(XLogReaderState *state, char **errormsg)
 		 * XLogBeginRead() or XLogNextRecord(), and is the location of the
 		 * error.
 		 */
-		Assert(!XLogRecPtrIsInvalid(state->EndRecPtr));
+		Assert(XLogRecPtrIsValid(state->EndRecPtr));
 
 		return NULL;
 	}
@@ -1398,7 +1398,7 @@ XLogFindNextRecord(XLogReaderState *state, XLogRecPtr RecPtr)
 	XLogPageHeader header;
 	char	   *errormsg;
 
-	Assert(!XLogRecPtrIsInvalid(RecPtr));
+	Assert(XLogRecPtrIsValid(RecPtr));
 
 	/* Make sure ReadPageInternal() can't return XLREAD_WOULDBLOCK. */
 	state->nonblocking = false;
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index 550de6e4a59..bb7b79613c2 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -773,7 +773,7 @@ InitWalRecovery(ControlFileData *ControlFile, bool *wasShutdown_ptr,
 		 * emit a log message when we continue initializing from a base
 		 * backup.
 		 */
-		if (!XLogRecPtrIsInvalid(ControlFile->backupStartPoint))
+		if (XLogRecPtrIsValid(ControlFile->backupStartPoint))
 			ereport(LOG,
 					errmsg("restarting backup recovery with redo LSN %X/%08X",
 						   LSN_FORMAT_ARGS(ControlFile->backupStartPoint)));
@@ -868,7 +868,7 @@ InitWalRecovery(ControlFileData *ControlFile, bool *wasShutdown_ptr,
 	 * The min recovery point should be part of the requested timeline's
 	 * history, too.
 	 */
-	if (!XLogRecPtrIsInvalid(ControlFile->minRecoveryPoint) &&
+	if (XLogRecPtrIsValid(ControlFile->minRecoveryPoint) &&
 		tliOfPointInHistory(ControlFile->minRecoveryPoint - 1, expectedTLEs) !=
 		ControlFile->minRecoveryPointTLI)
 		ereport(FATAL,
@@ -2204,7 +2204,7 @@ CheckRecoveryConsistency(void)
 	 * During crash recovery, we don't reach a consistent state until we've
 	 * replayed all the WAL.
 	 */
-	if (XLogRecPtrIsInvalid(minRecoveryPoint))
+	if (!XLogRecPtrIsValid(minRecoveryPoint))
 		return;
 
 	Assert(InArchiveRecovery);
@@ -2219,7 +2219,7 @@ CheckRecoveryConsistency(void)
 	/*
 	 * Have we reached the point where our base backup was completed?
 	 */
-	if (!XLogRecPtrIsInvalid(backupEndPoint) &&
+	if (XLogRecPtrIsValid(backupEndPoint) &&
 		backupEndPoint <= lastReplayedEndRecPtr)
 	{
 		XLogRecPtr	saveBackupStartPoint = backupStartPoint;
@@ -2425,7 +2425,7 @@ checkTimeLineSwitch(XLogRecPtr lsn, TimeLineID newTLI, TimeLineID prevTLI,
 	 * branched before the timeline the min recovery point is on, and you
 	 * attempt to do PITR to the new timeline.
 	 */
-	if (!XLogRecPtrIsInvalid(minRecoveryPoint) &&
+	if (XLogRecPtrIsValid(minRecoveryPoint) &&
 		lsn < minRecoveryPoint &&
 		newTLI > minRecoveryPointTLI)
 		ereport(PANIC,
@@ -3190,7 +3190,7 @@ ReadRecord(XLogPrefetcher *xlogprefetcher, int emode,
 			 * overwrite contrecord in the wrong place, breaking everything.
 			 */
 			if (!ArchiveRecoveryRequested &&
-				!XLogRecPtrIsInvalid(xlogreader->abortedRecPtr))
+				XLogRecPtrIsValid(xlogreader->abortedRecPtr))
 			{
 				abortedRecPtr = xlogreader->abortedRecPtr;
 				missingContrecPtr = xlogreader->missingContrecPtr;
diff --git a/src/backend/access/transam/xlogwait.c b/src/backend/access/transam/xlogwait.c
index e04567cfd67..6b4c1623e57 100644
--- a/src/backend/access/transam/xlogwait.c
+++ b/src/backend/access/transam/xlogwait.c
@@ -230,7 +230,7 @@ wakeupWaiters(WaitLSNType lsnType, XLogRecPtr currentLSN)
 			/* Get procInfo using appropriate heap node */
 			procInfo = pairingheap_container(WaitLSNProcInfo, heapNode[i], node);
 
-			if (!XLogRecPtrIsInvalid(currentLSN) && procInfo->waitLSN > currentLSN)
+			if (XLogRecPtrIsValid(currentLSN) && procInfo->waitLSN > currentLSN)
 				break;
 
 			Assert(numWakeUpProcs < WAKEUP_PROC_STATIC_ARRAY_SIZE);
diff --git a/src/backend/backup/backup_manifest.c b/src/backend/backup/backup_manifest.c
index d05252f383c..dd76c9b0b63 100644
--- a/src/backend/backup/backup_manifest.c
+++ b/src/backend/backup/backup_manifest.c
@@ -242,7 +242,7 @@ AddWALInfoToBackupManifest(backup_manifest_info *manifest, XLogRecPtr startptr,
 		 * entry->end is InvalidXLogRecPtr, it means that the timeline has not
 		 * yet ended.)
 		 */
-		if (!XLogRecPtrIsInvalid(entry->end) && entry->end < startptr)
+		if (XLogRecPtrIsValid(entry->end) && entry->end < startptr)
 			continue;
 
 		/*
@@ -274,7 +274,7 @@ AddWALInfoToBackupManifest(backup_manifest_info *manifest, XLogRecPtr startptr,
 			 * better have arrived at the expected starting TLI. If not,
 			 * something's gone horribly wrong.
 			 */
-			if (XLogRecPtrIsInvalid(entry->begin))
+			if (!XLogRecPtrIsValid(entry->begin))
 				ereport(ERROR,
 						errmsg("expected start timeline %u but found timeline %u",
 							   starttli, entry->tli));
diff --git a/src/backend/backup/basebackup_incremental.c b/src/backend/backup/basebackup_incremental.c
index a0d48ff0fef..852ab577045 100644
--- a/src/backend/backup/basebackup_incremental.c
+++ b/src/backend/backup/basebackup_incremental.c
@@ -519,7 +519,7 @@ PrepareForIncrementalBackup(IncrementalBackupInfo *ib,
 		if (!WalSummariesAreComplete(tli_wslist, tli_start_lsn, tli_end_lsn,
 									 &tli_missing_lsn))
 		{
-			if (XLogRecPtrIsInvalid(tli_missing_lsn))
+			if (!XLogRecPtrIsValid(tli_missing_lsn))
 				ereport(ERROR,
 						(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 						 errmsg("WAL summaries are required on timeline %u from %X/%08X to %X/%08X, but no summaries for that timeline and LSN range exist",
diff --git a/src/backend/backup/walsummary.c b/src/backend/backup/walsummary.c
index c7a2c65cc6a..2689eae3328 100644
--- a/src/backend/backup/walsummary.c
+++ b/src/backend/backup/walsummary.c
@@ -67,9 +67,9 @@ GetWalSummaries(TimeLineID tli, XLogRecPtr start_lsn, XLogRecPtr end_lsn)
 		/* Skip if it doesn't match the filter criteria. */
 		if (tli != 0 && tli != file_tli)
 			continue;
-		if (!XLogRecPtrIsInvalid(start_lsn) && start_lsn >= file_end_lsn)
+		if (XLogRecPtrIsValid(start_lsn) && start_lsn >= file_end_lsn)
 			continue;
-		if (!XLogRecPtrIsInvalid(end_lsn) && end_lsn <= file_start_lsn)
+		if (XLogRecPtrIsValid(end_lsn) && end_lsn <= file_start_lsn)
 			continue;
 
 		/* Add it to the list. */
@@ -111,9 +111,9 @@ FilterWalSummaries(List *wslist, TimeLineID tli,
 		/* Skip if it doesn't match the filter criteria. */
 		if (tli != 0 && tli != ws->tli)
 			continue;
-		if (!XLogRecPtrIsInvalid(start_lsn) && start_lsn > ws->end_lsn)
+		if (XLogRecPtrIsValid(start_lsn) && start_lsn > ws->end_lsn)
 			continue;
-		if (!XLogRecPtrIsInvalid(end_lsn) && end_lsn < ws->start_lsn)
+		if (XLogRecPtrIsValid(end_lsn) && end_lsn < ws->start_lsn)
 			continue;
 
 		/* Add it to the result list. */
diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c
index 3d29818badd..2b0c0ca8d05 100644
--- a/src/backend/commands/subscriptioncmds.c
+++ b/src/backend/commands/subscriptioncmds.c
@@ -393,7 +393,7 @@ parse_subscription_options(ParseState *pstate, List *stmt_options,
 				lsn = DatumGetLSN(DirectFunctionCall1(pg_lsn_in,
 													  CStringGetDatum(lsn_str)));
 
-				if (XLogRecPtrIsInvalid(lsn))
+				if (!XLogRecPtrIsValid(lsn))
 					ereport(ERROR,
 							(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 							 errmsg("invalid WAL location (LSN): %s", lsn_str)));
@@ -1895,7 +1895,7 @@ AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt,
 				 * If the user sets subskiplsn, we do a sanity check to make
 				 * sure that the specified LSN is a probable value.
 				 */
-				if (!XLogRecPtrIsInvalid(opts.lsn))
+				if (XLogRecPtrIsValid(opts.lsn))
 				{
 					RepOriginId originid;
 					char		originname[NAMEDATALEN];
@@ -1907,7 +1907,7 @@ AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt,
 					remote_lsn = replorigin_get_progress(originid, false);
 
 					/* Check the given LSN is at least a future LSN */
-					if (!XLogRecPtrIsInvalid(remote_lsn) && opts.lsn < remote_lsn)
+					if (XLogRecPtrIsValid(remote_lsn) && opts.lsn < remote_lsn)
 						ereport(ERROR,
 								(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 								 errmsg("skip WAL location (LSN %X/%08X) must be greater than origin LSN %X/%08X",
diff --git a/src/backend/postmaster/walsummarizer.c b/src/backend/postmaster/walsummarizer.c
index e1f142f20c7..c4a888a081c 100644
--- a/src/backend/postmaster/walsummarizer.c
+++ b/src/backend/postmaster/walsummarizer.c
@@ -342,7 +342,7 @@ WalSummarizerMain(const void *startup_data, size_t startup_data_len)
 	 * If we discover that WAL summarization is not enabled, just exit.
 	 */
 	current_lsn = GetOldestUnsummarizedLSN(&current_tli, &exact);
-	if (XLogRecPtrIsInvalid(current_lsn))
+	if (!XLogRecPtrIsValid(current_lsn))
 		proc_exit(0);
 
 	/*
@@ -379,7 +379,7 @@ WalSummarizerMain(const void *startup_data, size_t startup_data_len)
 		 * only have to do this once per timeline switch, we probably wouldn't
 		 * save any significant amount of work in practice.
 		 */
-		if (current_tli != latest_tli && XLogRecPtrIsInvalid(switch_lsn))
+		if (current_tli != latest_tli && !XLogRecPtrIsValid(switch_lsn))
 		{
 			List	   *tles = readTimeLineHistory(latest_tli);
 
@@ -394,7 +394,7 @@ WalSummarizerMain(const void *startup_data, size_t startup_data_len)
 		 * on this timeline. Switch to the next timeline and go around again,
 		 * backing up to the exact switch point if we passed it.
 		 */
-		if (!XLogRecPtrIsInvalid(switch_lsn) && current_lsn >= switch_lsn)
+		if (XLogRecPtrIsValid(switch_lsn) && current_lsn >= switch_lsn)
 		{
 			/* Restart summarization from switch point. */
 			current_tli = switch_tli;
@@ -419,7 +419,7 @@ WalSummarizerMain(const void *startup_data, size_t startup_data_len)
 		end_of_summary_lsn = SummarizeWAL(current_tli,
 										  current_lsn, exact,
 										  switch_lsn, latest_lsn);
-		Assert(!XLogRecPtrIsInvalid(end_of_summary_lsn));
+		Assert(XLogRecPtrIsValid(end_of_summary_lsn));
 		Assert(end_of_summary_lsn >= current_lsn);
 
 		/*
@@ -923,7 +923,7 @@ SummarizeWAL(TimeLineID tli, XLogRecPtr start_lsn, bool exact,
 	private_data = (SummarizerReadLocalXLogPrivate *)
 		palloc0(sizeof(SummarizerReadLocalXLogPrivate));
 	private_data->tli = tli;
-	private_data->historic = !XLogRecPtrIsInvalid(switch_lsn);
+	private_data->historic = XLogRecPtrIsValid(switch_lsn);
 	private_data->read_upto = maximum_lsn;
 
 	/* Create xlogreader. */
@@ -971,7 +971,7 @@ SummarizeWAL(TimeLineID tli, XLogRecPtr start_lsn, bool exact,
 	else
 	{
 		summary_start_lsn = XLogFindNextRecord(xlogreader, start_lsn);
-		if (XLogRecPtrIsInvalid(summary_start_lsn))
+		if (!XLogRecPtrIsValid(summary_start_lsn))
 		{
 			/*
 			 * If we hit end-of-WAL while trying to find the next valid
@@ -1058,7 +1058,7 @@ SummarizeWAL(TimeLineID tli, XLogRecPtr start_lsn, bool exact,
 		/* We shouldn't go backward. */
 		Assert(summary_start_lsn <= xlogreader->EndRecPtr);
 
-		if (!XLogRecPtrIsInvalid(switch_lsn) &&
+		if (XLogRecPtrIsValid(switch_lsn) &&
 			xlogreader->ReadRecPtr >= switch_lsn)
 		{
 			/*
@@ -1180,7 +1180,7 @@ SummarizeWAL(TimeLineID tli, XLogRecPtr start_lsn, bool exact,
 		 * If we have a switch LSN and have reached it, stop before reading
 		 * the next record.
 		 */
-		if (!XLogRecPtrIsInvalid(switch_lsn) &&
+		if (XLogRecPtrIsValid(switch_lsn) &&
 			xlogreader->EndRecPtr >= switch_lsn)
 			break;
 	}
@@ -1723,7 +1723,7 @@ MaybeRemoveOldWalSummaries(void)
 			 * If the WAL doesn't exist any more, we can remove it if the file
 			 * modification time is old enough.
 			 */
-			if (XLogRecPtrIsInvalid(oldest_lsn) || ws->end_lsn <= oldest_lsn)
+			if (!XLogRecPtrIsValid(oldest_lsn) || ws->end_lsn <= oldest_lsn)
 				RemoveWalSummaryIfOlderThan(ws, cutoff_time);
 
 			/*
diff --git a/src/backend/replication/logical/applyparallelworker.c b/src/backend/replication/logical/applyparallelworker.c
index 14325581afc..baa68c1ab6c 100644
--- a/src/backend/replication/logical/applyparallelworker.c
+++ b/src/backend/replication/logical/applyparallelworker.c
@@ -299,7 +299,7 @@ pa_can_start(void)
 	 * STREAM START message, and it doesn't seem worth sending the extra eight
 	 * bytes with the STREAM START to enable parallelism for this case.
 	 */
-	if (!XLogRecPtrIsInvalid(MySubscription->skiplsn))
+	if (XLogRecPtrIsValid(MySubscription->skiplsn))
 		return false;
 
 	/*
@@ -1640,7 +1640,7 @@ pa_xact_finish(ParallelApplyWorkerInfo *winfo, XLogRecPtr remote_lsn)
 	 */
 	pa_wait_for_xact_finish(winfo);
 
-	if (!XLogRecPtrIsInvalid(remote_lsn))
+	if (XLogRecPtrIsValid(remote_lsn))
 		store_flush_position(remote_lsn, winfo->shared->last_commit_end);
 
 	pa_free_worker(winfo);
diff --git a/src/backend/replication/logical/launcher.c b/src/backend/replication/logical/launcher.c
index 6c6d4015ba7..6214028eda9 100644
--- a/src/backend/replication/logical/launcher.c
+++ b/src/backend/replication/logical/launcher.c
@@ -1661,7 +1661,7 @@ pg_stat_get_subscription(PG_FUNCTION_ARGS)
 		else
 			nulls[3] = true;
 
-		if (XLogRecPtrIsInvalid(worker.last_lsn))
+		if (!XLogRecPtrIsValid(worker.last_lsn))
 			nulls[4] = true;
 		else
 			values[4] = LSNGetDatum(worker.last_lsn);
@@ -1673,7 +1673,7 @@ pg_stat_get_subscription(PG_FUNCTION_ARGS)
 			nulls[6] = true;
 		else
 			values[6] = TimestampTzGetDatum(worker.last_recv_time);
-		if (XLogRecPtrIsInvalid(worker.reply_lsn))
+		if (!XLogRecPtrIsValid(worker.reply_lsn))
 			nulls[7] = true;
 		else
 			values[7] = LSNGetDatum(worker.reply_lsn);
diff --git a/src/backend/replication/logical/logical.c b/src/backend/replication/logical/logical.c
index 93ed2eb368e..79717b52941 100644
--- a/src/backend/replication/logical/logical.c
+++ b/src/backend/replication/logical/logical.c
@@ -388,7 +388,7 @@ CreateInitDecodingContext(const char *plugin,
 	slot->data.plugin = plugin_name;
 	SpinLockRelease(&slot->mutex);
 
-	if (XLogRecPtrIsInvalid(restart_lsn))
+	if (!XLogRecPtrIsValid(restart_lsn))
 		ReplicationSlotReserveWal();
 	else
 	{
diff --git a/src/backend/replication/logical/logicalfuncs.c b/src/backend/replication/logical/logicalfuncs.c
index 25f890ddeed..d78e486bca6 100644
--- a/src/backend/replication/logical/logicalfuncs.c
+++ b/src/backend/replication/logical/logicalfuncs.c
@@ -229,7 +229,7 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin
 		 * Wait for specified streaming replication standby servers (if any)
 		 * to confirm receipt of WAL up to wait_for_wal_lsn.
 		 */
-		if (XLogRecPtrIsInvalid(upto_lsn))
+		if (!XLogRecPtrIsValid(upto_lsn))
 			wait_for_wal_lsn = end_of_wal;
 		else
 			wait_for_wal_lsn = Min(upto_lsn, end_of_wal);
diff --git a/src/backend/replication/logical/slotsync.c b/src/backend/replication/logical/slotsync.c
index b122d99b009..8b4afd87dc9 100644
--- a/src/backend/replication/logical/slotsync.c
+++ b/src/backend/replication/logical/slotsync.c
@@ -493,7 +493,7 @@ reserve_wal_for_local_slot(XLogRecPtr restart_lsn)
 	ReplicationSlot *slot = MyReplicationSlot;
 
 	Assert(slot != NULL);
-	Assert(XLogRecPtrIsInvalid(slot->data.restart_lsn));
+	Assert(!XLogRecPtrIsValid(slot->data.restart_lsn));
 
 	while (true)
 	{
@@ -899,8 +899,8 @@ synchronize_slots(WalReceiverConn *wrconn)
 		 * pg_replication_slots view, then we can avoid fetching RS_EPHEMERAL
 		 * slots in the first place.
 		 */
-		if ((XLogRecPtrIsInvalid(remote_slot->restart_lsn) ||
-			 XLogRecPtrIsInvalid(remote_slot->confirmed_lsn) ||
+		if ((!XLogRecPtrIsValid(remote_slot->restart_lsn) ||
+			 !XLogRecPtrIsValid(remote_slot->confirmed_lsn) ||
 			 !TransactionIdIsValid(remote_slot->catalog_xmin)) &&
 			remote_slot->invalidated == RS_INVAL_NONE)
 			pfree(remote_slot);
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index e1c757c911e..28f61f96a1a 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -514,7 +514,7 @@ bool		InitializingApplyWorker = false;
  * by the user.
  */
 static XLogRecPtr skip_xact_finish_lsn = InvalidXLogRecPtr;
-#define is_skipping_changes() (unlikely(!XLogRecPtrIsInvalid(skip_xact_finish_lsn)))
+#define is_skipping_changes() (unlikely(XLogRecPtrIsValid(skip_xact_finish_lsn)))
 
 /* BufFile handle of the current streaming file */
 static BufFile *stream_fd = NULL;
@@ -4126,7 +4126,7 @@ LogicalRepApplyLoop(XLogRecPtr last_received)
 						 * due to a bug, we don't want to proceed as it can
 						 * incorrectly advance oldest_nonremovable_xid.
 						 */
-						if (XLogRecPtrIsInvalid(rdt_data.remote_lsn))
+						if (!XLogRecPtrIsValid(rdt_data.remote_lsn))
 							elog(ERROR, "cannot get the latest WAL position from the publisher");
 
 						maybe_advance_nonremovable_xid(&rdt_data, true);
@@ -4613,7 +4613,7 @@ wait_for_publisher_status(RetainDeadTuplesData *rdt_data,
 static void
 wait_for_local_flush(RetainDeadTuplesData *rdt_data)
 {
-	Assert(!XLogRecPtrIsInvalid(rdt_data->remote_lsn) &&
+	Assert(XLogRecPtrIsValid(rdt_data->remote_lsn) &&
 		   TransactionIdIsValid(rdt_data->candidate_xid));
 
 	/*
@@ -6031,7 +6031,7 @@ maybe_start_skipping_changes(XLogRecPtr finish_lsn)
 	 * function is called for every remote transaction and we assume that
 	 * skipping the transaction is not used often.
 	 */
-	if (likely(XLogRecPtrIsInvalid(MySubscription->skiplsn) ||
+	if (likely(!XLogRecPtrIsValid(MySubscription->skiplsn) ||
 			   MySubscription->skiplsn != finish_lsn))
 		return;
 
@@ -6077,7 +6077,7 @@ clear_subscription_skip_lsn(XLogRecPtr finish_lsn)
 	XLogRecPtr	myskiplsn = MySubscription->skiplsn;
 	bool		started_tx = false;
 
-	if (likely(XLogRecPtrIsInvalid(myskiplsn)) || am_parallel_apply_worker())
+	if (likely(!XLogRecPtrIsValid(myskiplsn)) || am_parallel_apply_worker())
 		return;
 
 	if (!IsTransactionState())
@@ -6173,7 +6173,7 @@ apply_error_callback(void *arg)
 			errcontext("processing remote data for replication origin \"%s\" during message type \"%s\"",
 					   errarg->origin_name,
 					   logicalrep_message_type(errarg->command));
-		else if (XLogRecPtrIsInvalid(errarg->finish_lsn))
+		else if (!XLogRecPtrIsValid(errarg->finish_lsn))
 			errcontext("processing remote data for replication origin \"%s\" during message type \"%s\" in transaction %u",
 					   errarg->origin_name,
 					   logicalrep_message_type(errarg->command),
@@ -6189,7 +6189,7 @@ apply_error_callback(void *arg)
 	{
 		if (errarg->remote_attnum < 0)
 		{
-			if (XLogRecPtrIsInvalid(errarg->finish_lsn))
+			if (!XLogRecPtrIsValid(errarg->finish_lsn))
 				errcontext("processing remote data for replication origin \"%s\" during message type \"%s\" for replication target relation \"%s.%s\" in transaction %u",
 						   errarg->origin_name,
 						   logicalrep_message_type(errarg->command),
@@ -6207,7 +6207,7 @@ apply_error_callback(void *arg)
 		}
 		else
 		{
-			if (XLogRecPtrIsInvalid(errarg->finish_lsn))
+			if (!XLogRecPtrIsValid(errarg->finish_lsn))
 				errcontext("processing remote data for replication origin \"%s\" during message type \"%s\" for replication target relation \"%s.%s\" column \"%s\" in transaction %u",
 						   errarg->origin_name,
 						   logicalrep_message_type(errarg->command),
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index 6363030808f..0cb93dc90f2 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -1730,7 +1730,7 @@ static inline bool
 CanInvalidateIdleSlot(ReplicationSlot *s)
 {
 	return (idle_replication_slot_timeout_secs != 0 &&
-			!XLogRecPtrIsInvalid(s->data.restart_lsn) &&
+			XLogRecPtrIsValid(s->data.restart_lsn) &&
 			s->inactive_since > 0 &&
 			!(RecoveryInProgress() && s->data.synced));
 }
@@ -2922,7 +2922,7 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
 	 * Don't need to wait for the standbys to catch up if they are already
 	 * beyond the specified WAL location.
 	 */
-	if (!XLogRecPtrIsInvalid(ss_oldest_flush_lsn) &&
+	if (XLogRecPtrIsValid(ss_oldest_flush_lsn) &&
 		ss_oldest_flush_lsn >= wait_for_lsn)
 		return true;
 
@@ -2993,7 +2993,7 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
 			break;
 		}
 
-		if (XLogRecPtrIsInvalid(restart_lsn) || restart_lsn < wait_for_lsn)
+		if (!XLogRecPtrIsValid(restart_lsn) || restart_lsn < wait_for_lsn)
 		{
 			/* Log a message if no active_pid for this physical slot */
 			if (inactive)
@@ -3012,7 +3012,7 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
 
 		Assert(restart_lsn >= wait_for_lsn);
 
-		if (XLogRecPtrIsInvalid(min_restart_lsn) ||
+		if (!XLogRecPtrIsValid(min_restart_lsn) ||
 			min_restart_lsn > restart_lsn)
 			min_restart_lsn = restart_lsn;
 
@@ -3031,7 +3031,7 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
 		return false;
 
 	/* The ss_oldest_flush_lsn must not retreat. */
-	Assert(XLogRecPtrIsInvalid(ss_oldest_flush_lsn) ||
+	Assert(!XLogRecPtrIsValid(ss_oldest_flush_lsn) ||
 		   min_restart_lsn >= ss_oldest_flush_lsn);
 
 	ss_oldest_flush_lsn = min_restart_lsn;
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index b8f21153e7b..5aecd5c6a50 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -46,7 +46,7 @@ create_physical_replication_slot(char *name, bool immediately_reserve,
 	if (immediately_reserve)
 	{
 		/* Reserve WAL as the user asked for it */
-		if (XLogRecPtrIsInvalid(restart_lsn))
+		if (!XLogRecPtrIsValid(restart_lsn))
 			ReplicationSlotReserveWal();
 		else
 			MyReplicationSlot->data.restart_lsn = restart_lsn;
@@ -357,7 +357,7 @@ pg_get_replication_slots(PG_FUNCTION_ARGS)
 				 *
 				 * If we do change it, save the state for safe_wal_size below.
 				 */
-				if (!XLogRecPtrIsInvalid(slot_contents.data.restart_lsn))
+				if (XLogRecPtrIsValid(slot_contents.data.restart_lsn))
 				{
 					int			pid;
 
@@ -407,7 +407,7 @@ pg_get_replication_slots(PG_FUNCTION_ARGS)
 		values[i++] = BoolGetDatum(slot_contents.data.two_phase);
 
 		if (slot_contents.data.two_phase &&
-			!XLogRecPtrIsInvalid(slot_contents.data.two_phase_at))
+			XLogRecPtrIsValid(slot_contents.data.two_phase_at))
 			values[i++] = LSNGetDatum(slot_contents.data.two_phase_at);
 		else
 			nulls[i++] = true;
@@ -523,7 +523,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 
 	CheckSlotPermissions();
 
-	if (XLogRecPtrIsInvalid(moveto))
+	if (!XLogRecPtrIsValid(moveto))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("invalid target WAL LSN")));
@@ -545,7 +545,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	ReplicationSlotAcquire(NameStr(*slotname), true, true);
 
 	/* A slot whose restart_lsn has never been reserved cannot be advanced */
-	if (XLogRecPtrIsInvalid(MyReplicationSlot->data.restart_lsn))
+	if (!XLogRecPtrIsValid(MyReplicationSlot->data.restart_lsn))
 		ereport(ERROR,
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 				 errmsg("replication slot \"%s\" cannot be advanced",
@@ -679,7 +679,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 						NameStr(*src_name))));
 
 	/* Copying non-reserved slot doesn't make sense */
-	if (XLogRecPtrIsInvalid(src_restart_lsn))
+	if (!XLogRecPtrIsValid(src_restart_lsn))
 		ereport(ERROR,
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 				 errmsg("cannot copy a replication slot that doesn't reserve WAL")));
@@ -785,7 +785,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 					 errdetail("The source replication slot was modified incompatibly during the copy operation.")));
 
 		/* The source slot must have a consistent snapshot */
-		if (src_islogical && XLogRecPtrIsInvalid(copy_confirmed_flush))
+		if (src_islogical && !XLogRecPtrIsValid(copy_confirmed_flush))
 			ereport(ERROR,
 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 					 errmsg("cannot copy unfinished logical replication slot \"%s\"",
@@ -840,7 +840,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 	/* All done.  Set up the return values */
 	values[0] = NameGetDatum(dst_name);
 	nulls[0] = false;
-	if (!XLogRecPtrIsInvalid(MyReplicationSlot->data.confirmed_flush))
+	if (XLogRecPtrIsValid(MyReplicationSlot->data.confirmed_flush))
 	{
 		values[1] = LSNGetDatum(MyReplicationSlot->data.confirmed_flush);
 		nulls[1] = false;
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index 32cf3a48b89..a0c79958fd5 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -493,7 +493,7 @@ SyncRepReleaseWaiters(void)
 	if (MyWalSnd->sync_standby_priority == 0 ||
 		(MyWalSnd->state != WALSNDSTATE_STREAMING &&
 		 MyWalSnd->state != WALSNDSTATE_STOPPING) ||
-		XLogRecPtrIsInvalid(MyWalSnd->flush))
+		!XLogRecPtrIsValid(MyWalSnd->flush))
 	{
 		announce_next_takeover = true;
 		return;
@@ -676,11 +676,11 @@ SyncRepGetOldestSyncRecPtr(XLogRecPtr *writePtr,
 		XLogRecPtr	flush = sync_standbys[i].flush;
 		XLogRecPtr	apply = sync_standbys[i].apply;
 
-		if (XLogRecPtrIsInvalid(*writePtr) || *writePtr > write)
+		if (!XLogRecPtrIsValid(*writePtr) || *writePtr > write)
 			*writePtr = write;
-		if (XLogRecPtrIsInvalid(*flushPtr) || *flushPtr > flush)
+		if (!XLogRecPtrIsValid(*flushPtr) || *flushPtr > flush)
 			*flushPtr = flush;
-		if (XLogRecPtrIsInvalid(*applyPtr) || *applyPtr > apply)
+		if (!XLogRecPtrIsValid(*applyPtr) || *applyPtr > apply)
 			*applyPtr = apply;
 	}
 }
@@ -799,7 +799,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 			continue;
 
 		/* Must have a valid flush position */
-		if (XLogRecPtrIsInvalid(stby->flush))
+		if (!XLogRecPtrIsValid(stby->flush))
 			continue;
 
 		/* OK, it's a candidate */
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index 7361ffc9dcf..2ee8fecee26 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1469,16 +1469,16 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	{
 		values[1] = CStringGetTextDatum(WalRcvGetStateString(state));
 
-		if (XLogRecPtrIsInvalid(receive_start_lsn))
+		if (!XLogRecPtrIsValid(receive_start_lsn))
 			nulls[2] = true;
 		else
 			values[2] = LSNGetDatum(receive_start_lsn);
 		values[3] = Int32GetDatum(receive_start_tli);
-		if (XLogRecPtrIsInvalid(written_lsn))
+		if (!XLogRecPtrIsValid(written_lsn))
 			nulls[4] = true;
 		else
 			values[4] = LSNGetDatum(written_lsn);
-		if (XLogRecPtrIsInvalid(flushed_lsn))
+		if (!XLogRecPtrIsValid(flushed_lsn))
 			nulls[5] = true;
 		else
 			values[5] = LSNGetDatum(flushed_lsn);
@@ -1491,7 +1491,7 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 			nulls[8] = true;
 		else
 			values[8] = TimestampTzGetDatum(last_receipt_time);
-		if (XLogRecPtrIsInvalid(latest_end_lsn))
+		if (!XLogRecPtrIsValid(latest_end_lsn))
 			nulls[9] = true;
 		else
 			values[9] = LSNGetDatum(latest_end_lsn);
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 548eafa7a73..b6dfb230d0d 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -529,7 +529,7 @@ ReadReplicationSlot(ReadReplicationSlotCmd *cmd)
 		i++;
 
 		/* start LSN */
-		if (!XLogRecPtrIsInvalid(slot_contents.data.restart_lsn))
+		if (XLogRecPtrIsValid(slot_contents.data.restart_lsn))
 		{
 			char		xloc[64];
 
@@ -541,7 +541,7 @@ ReadReplicationSlot(ReadReplicationSlotCmd *cmd)
 		i++;
 
 		/* timeline this WAL was produced on */
-		if (!XLogRecPtrIsInvalid(slot_contents.data.restart_lsn))
+		if (XLogRecPtrIsValid(slot_contents.data.restart_lsn))
 		{
 			TimeLineID	slots_position_timeline;
 			TimeLineID	current_timeline;
@@ -906,7 +906,7 @@ StartReplication(StartReplicationCmd *cmd)
 			 * that's older than the switchpoint, if it's still in the same
 			 * WAL segment.
 			 */
-			if (!XLogRecPtrIsInvalid(switchpoint) &&
+			if (XLogRecPtrIsValid(switchpoint) &&
 				switchpoint < cmd->startpoint)
 			{
 				ereport(ERROR,
@@ -1827,7 +1827,7 @@ WalSndWaitForWal(XLogRecPtr loc)
 	 * receipt of WAL up to RecentFlushPtr. This is particularly interesting
 	 * if we're far behind.
 	 */
-	if (!XLogRecPtrIsInvalid(RecentFlushPtr) &&
+	if (XLogRecPtrIsValid(RecentFlushPtr) &&
 		!NeedToWaitForWal(loc, RecentFlushPtr, &wait_event))
 		return RecentFlushPtr;
 
@@ -3597,7 +3597,7 @@ WalSndDone(WalSndSendDataCallback send_data)
 	 * flush location if valid, write otherwise. Tools like pg_receivewal will
 	 * usually (unless in synchronous mode) return an invalid flush location.
 	 */
-	replicatedPtr = XLogRecPtrIsInvalid(MyWalSnd->flush) ?
+	replicatedPtr = !XLogRecPtrIsValid(MyWalSnd->flush) ?
 		MyWalSnd->write : MyWalSnd->flush;
 
 	if (WalSndCaughtUp && sentPtr == replicatedPtr &&
@@ -4073,19 +4073,19 @@ pg_stat_get_wal_senders(PG_FUNCTION_ARGS)
 		{
 			values[1] = CStringGetTextDatum(WalSndGetStateString(state));
 
-			if (XLogRecPtrIsInvalid(sent_ptr))
+			if (!XLogRecPtrIsValid(sent_ptr))
 				nulls[2] = true;
 			values[2] = LSNGetDatum(sent_ptr);
 
-			if (XLogRecPtrIsInvalid(write))
+			if (!XLogRecPtrIsValid(write))
 				nulls[3] = true;
 			values[3] = LSNGetDatum(write);
 
-			if (XLogRecPtrIsInvalid(flush))
+			if (!XLogRecPtrIsValid(flush))
 				nulls[4] = true;
 			values[4] = LSNGetDatum(flush);
 
-			if (XLogRecPtrIsInvalid(apply))
+			if (!XLogRecPtrIsValid(apply))
 				nulls[5] = true;
 			values[5] = LSNGetDatum(apply);
 
@@ -4094,7 +4094,7 @@ pg_stat_get_wal_senders(PG_FUNCTION_ARGS)
 			 * which always returns an invalid flush location, as an
 			 * asynchronous standby.
 			 */
-			priority = XLogRecPtrIsInvalid(flush) ? 0 : priority;
+			priority = !XLogRecPtrIsValid(flush) ? 0 : priority;
 
 			if (writeLag < 0)
 				nulls[6] = true;
@@ -4165,7 +4165,7 @@ WalSndKeepalive(bool requestReply, XLogRecPtr writePtr)
 	/* construct the message... */
 	resetStringInfo(&output_message);
 	pq_sendbyte(&output_message, PqReplMsg_Keepalive);
-	pq_sendint64(&output_message, XLogRecPtrIsInvalid(writePtr) ? sentPtr : writePtr);
+	pq_sendint64(&output_message, !XLogRecPtrIsValid(writePtr) ? sentPtr : writePtr);
 	pq_sendint64(&output_message, GetCurrentTimestamp());
 	pq_sendbyte(&output_message, requestReply ? 1 : 0);
 
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 00719c7aea2..f830f2c6ff3 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -5545,7 +5545,7 @@ MarkBufferDirtyHint(Buffer buffer, bool buffer_std)
 			 * checksum here. That will happen when the page is written
 			 * sometime later in this checkpoint cycle.
 			 */
-			if (!XLogRecPtrIsInvalid(lsn))
+			if (XLogRecPtrIsValid(lsn))
 				PageSetLSN(page, lsn);
 		}
 
diff --git a/src/bin/pg_basebackup/pg_receivewal.c b/src/bin/pg_basebackup/pg_receivewal.c
index 289ca14dcfe..3e6f4a7fc48 100644
--- a/src/bin/pg_basebackup/pg_receivewal.c
+++ b/src/bin/pg_basebackup/pg_receivewal.c
@@ -192,7 +192,7 @@ stop_streaming(XLogRecPtr xlogpos, uint32 timeline, bool segment_finished)
 					LSN_FORMAT_ARGS(xlogpos),
 					timeline);
 
-	if (!XLogRecPtrIsInvalid(endpos) && endpos < xlogpos)
+	if (XLogRecPtrIsValid(endpos) && endpos < xlogpos)
 	{
 		if (verbose)
 			pg_log_info("stopped log streaming at %X/%08X (timeline %u)",
diff --git a/src/bin/pg_basebackup/pg_recvlogical.c b/src/bin/pg_basebackup/pg_recvlogical.c
index 7a4d1a2d2ca..6739784a993 100644
--- a/src/bin/pg_basebackup/pg_recvlogical.c
+++ b/src/bin/pg_basebackup/pg_recvlogical.c
@@ -1080,7 +1080,7 @@ prepareToTerminate(PGconn *conn, XLogRecPtr endpos, StreamStopReason reason,
 							LSN_FORMAT_ARGS(endpos));
 				break;
 			case STREAM_STOP_END_OF_WAL:
-				Assert(!XLogRecPtrIsInvalid(lsn));
+				Assert(XLogRecPtrIsValid(lsn));
 				pg_log_info("end position %X/%08X reached by WAL record at %X/%08X",
 							LSN_FORMAT_ARGS(endpos), LSN_FORMAT_ARGS(lsn));
 				break;
diff --git a/src/bin/pg_rewind/pg_rewind.c b/src/bin/pg_rewind/pg_rewind.c
index 1b953692b17..27c514f934a 100644
--- a/src/bin/pg_rewind/pg_rewind.c
+++ b/src/bin/pg_rewind/pg_rewind.c
@@ -850,9 +850,9 @@ progress_report(bool finished)
 static XLogRecPtr
 MinXLogRecPtr(XLogRecPtr a, XLogRecPtr b)
 {
-	if (XLogRecPtrIsInvalid(a))
+	if (!XLogRecPtrIsValid(a))
 		return b;
-	else if (XLogRecPtrIsInvalid(b))
+	else if (!XLogRecPtrIsValid(b))
 		return a;
 	else
 		return Min(a, b);
diff --git a/src/bin/pg_waldump/pg_waldump.c b/src/bin/pg_waldump/pg_waldump.c
index 13d3ec2f5be..19cf5461eac 100644
--- a/src/bin/pg_waldump/pg_waldump.c
+++ b/src/bin/pg_waldump/pg_waldump.c
@@ -637,7 +637,7 @@ XLogDumpDisplayStats(XLogDumpConfig *config, XLogStats *stats)
 	/*
 	 * Leave if no stats have been computed yet, as tracked by the end LSN.
 	 */
-	if (XLogRecPtrIsInvalid(stats->endptr))
+	if (!XLogRecPtrIsValid(stats->endptr))
 		return;
 
 	/*
@@ -1136,7 +1136,7 @@ main(int argc, char **argv)
 		/* parse position from file */
 		XLogFromFileName(fname, &private.timeline, &segno, WalSegSz);
 
-		if (XLogRecPtrIsInvalid(private.startptr))
+		if (!XLogRecPtrIsValid(private.startptr))
 			XLogSegNoOffsetToRecPtr(segno, 0, WalSegSz, private.startptr);
 		else if (!XLByteInSeg(private.startptr, segno, WalSegSz))
 		{
@@ -1147,7 +1147,7 @@ main(int argc, char **argv)
 		}
 
 		/* no second file specified, set end position */
-		if (!(optind + 1 < argc) && XLogRecPtrIsInvalid(private.endptr))
+		if (!(optind + 1 < argc) && !XLogRecPtrIsValid(private.endptr))
 			XLogSegNoOffsetToRecPtr(segno + 1, 0, WalSegSz, private.endptr);
 
 		/* parse ENDSEG if passed */
@@ -1170,7 +1170,7 @@ main(int argc, char **argv)
 				pg_fatal("ENDSEG %s is before STARTSEG %s",
 						 argv[optind + 1], argv[optind]);
 
-			if (XLogRecPtrIsInvalid(private.endptr))
+			if (!XLogRecPtrIsValid(private.endptr))
 				XLogSegNoOffsetToRecPtr(endsegno + 1, 0, WalSegSz,
 										private.endptr);
 
@@ -1192,7 +1192,7 @@ main(int argc, char **argv)
 		waldir = identify_target_directory(waldir, NULL);
 
 	/* we don't know what to print */
-	if (XLogRecPtrIsInvalid(private.startptr))
+	if (!XLogRecPtrIsValid(private.startptr))
 	{
 		pg_log_error("no start WAL location given");
 		goto bad_argument;
diff --git a/src/include/access/xlogdefs.h b/src/include/access/xlogdefs.h
index 2397fb24115..b16b2a1c8a3 100644
--- a/src/include/access/xlogdefs.h
+++ b/src/include/access/xlogdefs.h
@@ -26,8 +26,16 @@ typedef uint64 XLogRecPtr;
  * record can begin at zero.
  */
 #define InvalidXLogRecPtr	0
-#define XLogRecPtrIsInvalid(r)	((r) == InvalidXLogRecPtr)
+#define XLogRecPtrIsValid(r) ((r) != InvalidXLogRecPtr)
 
+/*
+ * New code should use XLogRecPtrIsValid() instead of XLogRecPtrIsInvalid()
+ * for consistency with the affirmative form of other *IsValid() macros and to
+ * avoid awkward double negative.
+ * This macro is retained for convenience of third-party code but could
+ * be deprecated in the future.
+ */
+#define XLogRecPtrIsInvalid(r)	((r) == InvalidXLogRecPtr)
 /*
  * First LSN to use for "fake" LSNs.
  *
-- 
2.34.1

v5-0002-Introduce-PG_DEPRECATED-and-deprecate-XLogRecPtrI.patchtext/x-diff; charset=us-asciiDownload
From 22f02ca0618d9f2e34de8fa084127bf500d75603 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Mon, 3 Nov 2025 06:33:01 +0000
Subject: [PATCH v5 2/4] Introduce PG_DEPRECATED() and deprecate
 XLogRecPtrIsInvalid()

This commit creates a new macro PG_DEPRECATED() to mark a declaration as
deprecated with a custom message. The compiler will emit a warning when the
deprecated entity is used.

Then it makes use of this new macro to emit a deprecated message about
XLogRecPtrIsInvalid() as of version 24 (means until the new macro is available
on all the supported major versions).
---
 src/include/access/xlogdefs.h | 14 +++++++++++---
 src/include/c.h               | 15 +++++++++++++++
 2 files changed, 26 insertions(+), 3 deletions(-)
  46.3% src/include/access/
  53.6% src/include/

diff --git a/src/include/access/xlogdefs.h b/src/include/access/xlogdefs.h
index b16b2a1c8a3..2589a21083b 100644
--- a/src/include/access/xlogdefs.h
+++ b/src/include/access/xlogdefs.h
@@ -32,10 +32,18 @@ typedef uint64 XLogRecPtr;
  * New code should use XLogRecPtrIsValid() instead of XLogRecPtrIsInvalid()
  * for consistency with the affirmative form of other *IsValid() macros and to
  * avoid awkward double negative.
- * This macro is retained for convenience of third-party code but could
- * be deprecated in the future.
+ * This function is retained for convenience of third-party code but is/will be
+ * deprecated as of version 24.
  */
-#define XLogRecPtrIsInvalid(r)	((r) == InvalidXLogRecPtr)
+#if PG_VERSION_NUM >= 240000
+PG_DEPRECATED("use XLogRecPtrIsValid() instead")
+#endif
+static inline bool
+XLogRecPtrIsInvalid(XLogRecPtr ptr)
+{
+	return ptr == InvalidXLogRecPtr;
+}
+
 /*
  * First LSN to use for "fake" LSNs.
  *
diff --git a/src/include/c.h b/src/include/c.h
index 757dfff4782..60e13cd5d6d 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -227,6 +227,21 @@
 #define PG_USED_FOR_ASSERTS_ONLY pg_attribute_unused()
 #endif
 
+/*
+ * Mark a declaration as deprecated with a custom message. The compiler will
+ * emit a warning when the deprecated entity is used.
+ */
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L || \
+defined(__cplusplus) && __cplusplus >= 201402L
+#define PG_DEPRECATED(msg) [[deprecated(msg)]]
+#elif defined(__GNUC__) || defined(__clang__)
+#define PG_DEPRECATED(msg) __attribute__((deprecated(msg)))
+#elif defined(_MSC_VER)
+#define PG_DEPRECATED(msg) __declspec(deprecated(msg))
+#else
+#define PG_DEPRECATED(msg)
+#endif
+
 /* GCC supports format attributes */
 #if defined(__GNUC__)
 #define pg_attribute_format_arg(a) __attribute__((format_arg(a)))
-- 
2.34.1

v5-0003-Replace-InvalidXLogRecPtr-comparisons-with-XLogRe.patchtext/x-diff; charset=us-asciiDownload
From 514da60b06ff7d5bdada38c2030afca535df4c67 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Wed, 29 Oct 2025 11:45:52 +0000
Subject: [PATCH v5 3/4] Replace InvalidXLogRecPtr comparisons with
 XLogRecPtrIsValid()

This commit ensures the XLogRecPtrIsValid() macro is used instead of direct
InvalidXLogRecPtr equality comparisons.
---
 src/backend/access/heap/rewriteheap.c         |  4 +-
 src/backend/access/heap/vacuumlazy.c          |  2 +-
 src/backend/access/transam/twophase.c         |  2 +-
 src/backend/access/transam/xlog.c             | 18 ++++-----
 src/backend/access/transam/xloginsert.c       |  4 +-
 src/backend/access/transam/xlogreader.c       |  2 +-
 src/backend/access/transam/xlogrecovery.c     |  8 ++--
 src/backend/access/transam/xlogutils.c        |  8 ++--
 src/backend/catalog/pg_subscription.c         |  4 +-
 src/backend/replication/logical/logical.c     | 30 +++++++--------
 .../replication/logical/logicalfuncs.c        |  4 +-
 src/backend/replication/logical/origin.c      | 18 ++++-----
 src/backend/replication/logical/proto.c       | 18 ++++-----
 .../replication/logical/reorderbuffer.c       | 38 +++++++++----------
 src/backend/replication/logical/snapbuild.c   | 14 +++----
 src/backend/replication/slot.c                | 18 ++++-----
 src/backend/replication/slotfuncs.c           |  6 +--
 src/backend/replication/walsender.c           |  6 +--
 src/bin/pg_basebackup/pg_receivewal.c         |  6 +--
 src/bin/pg_basebackup/pg_recvlogical.c        | 10 ++---
 src/bin/pg_waldump/pg_waldump.c               |  4 +-
 src/include/access/xlogdefs.h                 |  2 +-
 22 files changed, 113 insertions(+), 113 deletions(-)
  19.4% src/backend/access/transam/
  54.8% src/backend/replication/logical/
  12.3% src/backend/replication/
   3.6% src/backend/
   7.6% src/bin/pg_basebackup/

diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c
index 8061e92f044..66ab48f0fe0 100644
--- a/src/backend/access/heap/rewriteheap.c
+++ b/src/backend/access/heap/rewriteheap.c
@@ -1169,7 +1169,7 @@ CheckPointLogicalRewriteHeap(void)
 	cutoff = ReplicationSlotsComputeLogicalRestartLSN();
 
 	/* don't start earlier than the restart lsn */
-	if (cutoff != InvalidXLogRecPtr && redo < cutoff)
+	if (XLogRecPtrIsValid(cutoff) && redo < cutoff)
 		cutoff = redo;
 
 	mappings_dir = AllocateDir(PG_LOGICAL_MAPPINGS_DIR);
@@ -1204,7 +1204,7 @@ CheckPointLogicalRewriteHeap(void)
 
 		lsn = ((uint64) hi) << 32 | lo;
 
-		if (lsn < cutoff || cutoff == InvalidXLogRecPtr)
+		if (lsn < cutoff || !XLogRecPtrIsValid(cutoff))
 		{
 			elog(DEBUG1, "removing logical rewrite file \"%s\"", path);
 			if (unlink(path) < 0)
diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c
index 61fe623cc60..deb9a3dc0d1 100644
--- a/src/backend/access/heap/vacuumlazy.c
+++ b/src/backend/access/heap/vacuumlazy.c
@@ -1901,7 +1901,7 @@ lazy_scan_new_or_empty(LVRelState *vacrel, Buffer buf, BlockNumber blkno,
 			 * WAL-logged, and if not, do that now.
 			 */
 			if (RelationNeedsWAL(vacrel->rel) &&
-				PageGetLSN(page) == InvalidXLogRecPtr)
+				!XLogRecPtrIsValid(PageGetLSN(page)))
 				log_newpage_buffer(buf, true);
 
 			PageSetAllVisible(page);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 8a92b292e56..89d0bfa7760 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -2198,7 +2198,7 @@ ProcessTwoPhaseBuffer(FullTransactionId fxid,
 	Assert(LWLockHeldByMeInMode(TwoPhaseStateLock, LW_EXCLUSIVE));
 
 	if (!fromdisk)
-		Assert(prepare_start_lsn != InvalidXLogRecPtr);
+		Assert(XLogRecPtrIsValid(prepare_start_lsn));
 
 	/* Already processed? */
 	if (TransactionIdDidCommit(XidFromFullTransactionId(fxid)) ||
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 0564482cda8..101b616b028 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -849,7 +849,7 @@ XLogInsertRecord(XLogRecData *rdata,
 
 		if (doPageWrites &&
 			(!prevDoPageWrites ||
-			 (fpw_lsn != InvalidXLogRecPtr && fpw_lsn <= RedoRecPtr)))
+			 (XLogRecPtrIsValid(fpw_lsn) && fpw_lsn <= RedoRecPtr)))
 		{
 			/*
 			 * Oops, some buffer now needs to be backed up that the caller
@@ -883,7 +883,7 @@ XLogInsertRecord(XLogRecData *rdata,
 		 * Those checks are only needed for records that can contain buffer
 		 * references, and an XLOG_SWITCH record never does.
 		 */
-		Assert(fpw_lsn == InvalidXLogRecPtr);
+		Assert(!XLogRecPtrIsValid(fpw_lsn));
 		WALInsertLockAcquireExclusive();
 		inserted = ReserveXLogSwitch(&StartPos, &EndPos, &rechdr->xl_prev);
 	}
@@ -898,7 +898,7 @@ XLogInsertRecord(XLogRecData *rdata,
 		 * not check RedoRecPtr before inserting the record; we just need to
 		 * update it afterwards.
 		 */
-		Assert(fpw_lsn == InvalidXLogRecPtr);
+		Assert(!XLogRecPtrIsValid(fpw_lsn));
 		WALInsertLockAcquireExclusive();
 		ReserveXLogInsertLocation(rechdr->xl_tot_len, &StartPos, &EndPos,
 								  &rechdr->xl_prev);
@@ -1603,7 +1603,7 @@ WaitXLogInsertionsToFinish(XLogRecPtr upto)
 			 */
 		} while (insertingat < upto);
 
-		if (insertingat != InvalidXLogRecPtr && insertingat < finishedUpto)
+		if (XLogRecPtrIsValid(insertingat) && insertingat < finishedUpto)
 			finishedUpto = insertingat;
 	}
 
@@ -7363,7 +7363,7 @@ CreateCheckPoint(int flags)
 	 * Update the average distance between checkpoints if the prior checkpoint
 	 * exists.
 	 */
-	if (PriorRedoPtr != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(PriorRedoPtr))
 		UpdateCheckPointDistanceEstimate(RedoRecPtr - PriorRedoPtr);
 
 	INJECTION_POINT("checkpoint-before-old-wal-removal", NULL);
@@ -7811,7 +7811,7 @@ CreateRestartPoint(int flags)
 	 * Update the average distance between checkpoints/restartpoints if the
 	 * prior checkpoint exists.
 	 */
-	if (PriorRedoPtr != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(PriorRedoPtr))
 		UpdateCheckPointDistanceEstimate(RedoRecPtr - PriorRedoPtr);
 
 	/*
@@ -8018,7 +8018,7 @@ KeepLogSeg(XLogRecPtr recptr, XLogSegNo *logSegNo)
 
 	/* Calculate how many segments are kept by slots. */
 	keep = XLogGetReplicationSlotMinimumLSN();
-	if (keep != InvalidXLogRecPtr && keep < recptr)
+	if (XLogRecPtrIsValid(keep) && keep < recptr)
 	{
 		XLByteToSeg(keep, segno, wal_segment_size);
 
@@ -8045,7 +8045,7 @@ KeepLogSeg(XLogRecPtr recptr, XLogSegNo *logSegNo)
 	 * summarized.
 	 */
 	keep = GetOldestUnsummarizedLSN(NULL, NULL);
-	if (keep != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(keep))
 	{
 		XLogSegNo	unsummarized_segno;
 
@@ -8603,7 +8603,7 @@ xlog_redo(XLogReaderState *record)
 			LocalMinRecoveryPoint = ControlFile->minRecoveryPoint;
 			LocalMinRecoveryPointTLI = ControlFile->minRecoveryPointTLI;
 		}
-		if (LocalMinRecoveryPoint != InvalidXLogRecPtr && LocalMinRecoveryPoint < lsn)
+		if (XLogRecPtrIsValid(LocalMinRecoveryPoint) && LocalMinRecoveryPoint < lsn)
 		{
 			TimeLineID	replayTLI;
 
diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c
index 58cb4b1b00c..a56d5a55282 100644
--- a/src/backend/access/transam/xloginsert.c
+++ b/src/backend/access/transam/xloginsert.c
@@ -528,7 +528,7 @@ XLogInsert(RmgrId rmid, uint8 info)
 
 		EndPos = XLogInsertRecord(rdt, fpw_lsn, curinsert_flags, num_fpi,
 								  fpi_bytes, topxid_included);
-	} while (EndPos == InvalidXLogRecPtr);
+	} while (!XLogRecPtrIsValid(EndPos));
 
 	XLogResetInsertion();
 
@@ -639,7 +639,7 @@ XLogRecordAssemble(RmgrId rmid, uint8 info,
 			needs_backup = (page_lsn <= RedoRecPtr);
 			if (!needs_backup)
 			{
-				if (*fpw_lsn == InvalidXLogRecPtr || page_lsn < *fpw_lsn)
+				if (!XLogRecPtrIsValid(*fpw_lsn) || page_lsn < *fpw_lsn)
 					*fpw_lsn = page_lsn;
 			}
 		}
diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index aad16127e60..755f351143a 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -558,7 +558,7 @@ XLogDecodeNextRecord(XLogReaderState *state, bool nonblocking)
 
 	RecPtr = state->NextRecPtr;
 
-	if (state->DecodeRecPtr != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(state->DecodeRecPtr))
 	{
 		/* read the record after the one we just read */
 
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index bb7b79613c2..b4ed57b0864 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -758,9 +758,9 @@ InitWalRecovery(ControlFileData *ControlFile, bool *wasShutdown_ptr,
 		 * end-of-backup record), and we can enter archive recovery directly.
 		 */
 		if (ArchiveRecoveryRequested &&
-			(ControlFile->minRecoveryPoint != InvalidXLogRecPtr ||
+			(XLogRecPtrIsValid(ControlFile->minRecoveryPoint) ||
 			 ControlFile->backupEndRequired ||
-			 ControlFile->backupEndPoint != InvalidXLogRecPtr ||
+			 XLogRecPtrIsValid(ControlFile->backupEndPoint) ||
 			 ControlFile->state == DB_SHUTDOWNED))
 		{
 			InArchiveRecovery = true;
@@ -3164,7 +3164,7 @@ ReadRecord(XLogPrefetcher *xlogprefetcher, int emode,
 	/* Pass through parameters to XLogPageRead */
 	private->fetching_ckpt = fetching_ckpt;
 	private->emode = emode;
-	private->randAccess = (xlogreader->ReadRecPtr == InvalidXLogRecPtr);
+	private->randAccess = (!XLogRecPtrIsValid(xlogreader->ReadRecPtr));
 	private->replayTLI = replayTLI;
 
 	/* This is the first attempt to read this page. */
@@ -4370,7 +4370,7 @@ XLogFileReadAnyTLI(XLogSegNo segno, XLogSource source)
 		 * Skip scanning the timeline ID that the logfile segment to read
 		 * doesn't belong to
 		 */
-		if (hent->begin != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(hent->begin))
 		{
 			XLogSegNo	beginseg = 0;
 
diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c
index 38176d9688e..ce2a3e42146 100644
--- a/src/backend/access/transam/xlogutils.c
+++ b/src/backend/access/transam/xlogutils.c
@@ -710,7 +710,7 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage,
 	const XLogRecPtr lastReadPage = (state->seg.ws_segno *
 									 state->segcxt.ws_segsize + state->segoff);
 
-	Assert(wantPage != InvalidXLogRecPtr && wantPage % XLOG_BLCKSZ == 0);
+	Assert(XLogRecPtrIsValid(wantPage) && wantPage % XLOG_BLCKSZ == 0);
 	Assert(wantLength <= XLOG_BLCKSZ);
 	Assert(state->readLen == 0 || state->readLen <= XLOG_BLCKSZ);
 	Assert(currTLI != 0);
@@ -741,7 +741,7 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage,
 	 */
 	if (state->currTLI == currTLI && wantPage >= lastReadPage)
 	{
-		Assert(state->currTLIValidUntil == InvalidXLogRecPtr);
+		Assert(!XLogRecPtrIsValid(state->currTLIValidUntil));
 		return;
 	}
 
@@ -750,7 +750,7 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage,
 	 * timeline and the timeline we're reading from is valid until the end of
 	 * the current segment we can just keep reading.
 	 */
-	if (state->currTLIValidUntil != InvalidXLogRecPtr &&
+	if (XLogRecPtrIsValid(state->currTLIValidUntil) &&
 		state->currTLI != currTLI &&
 		state->currTLI != 0 &&
 		((wantPage + wantLength) / state->segcxt.ws_segsize) <
@@ -790,7 +790,7 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage,
 		state->currTLIValidUntil = tliSwitchPoint(state->currTLI, timelineHistory,
 												  &state->nextTLI);
 
-		Assert(state->currTLIValidUntil == InvalidXLogRecPtr ||
+		Assert(!XLogRecPtrIsValid(state->currTLIValidUntil) ||
 			   wantPage + wantLength < state->currTLIValidUntil);
 
 		list_free_deep(timelineHistory);
diff --git a/src/backend/catalog/pg_subscription.c b/src/backend/catalog/pg_subscription.c
index 1945627ed88..180e77e9484 100644
--- a/src/backend/catalog/pg_subscription.c
+++ b/src/backend/catalog/pg_subscription.c
@@ -293,7 +293,7 @@ AddSubscriptionRelState(Oid subid, Oid relid, char state,
 	values[Anum_pg_subscription_rel_srsubid - 1] = ObjectIdGetDatum(subid);
 	values[Anum_pg_subscription_rel_srrelid - 1] = ObjectIdGetDatum(relid);
 	values[Anum_pg_subscription_rel_srsubstate - 1] = CharGetDatum(state);
-	if (sublsn != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(sublsn))
 		values[Anum_pg_subscription_rel_srsublsn - 1] = LSNGetDatum(sublsn);
 	else
 		nulls[Anum_pg_subscription_rel_srsublsn - 1] = true;
@@ -366,7 +366,7 @@ UpdateSubscriptionRelState(Oid subid, Oid relid, char state,
 	values[Anum_pg_subscription_rel_srsubstate - 1] = CharGetDatum(state);
 
 	replaces[Anum_pg_subscription_rel_srsublsn - 1] = true;
-	if (sublsn != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(sublsn))
 		values[Anum_pg_subscription_rel_srsublsn - 1] = LSNGetDatum(sublsn);
 	else
 		nulls[Anum_pg_subscription_rel_srsublsn - 1] = true;
diff --git a/src/backend/replication/logical/logical.c b/src/backend/replication/logical/logical.c
index 79717b52941..866f92cf799 100644
--- a/src/backend/replication/logical/logical.c
+++ b/src/backend/replication/logical/logical.c
@@ -546,9 +546,9 @@ CreateDecodingContext(XLogRecPtr start_lsn,
 
 	/* slot must be valid to allow decoding */
 	Assert(slot->data.invalidated == RS_INVAL_NONE);
-	Assert(slot->data.restart_lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(slot->data.restart_lsn));
 
-	if (start_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(start_lsn))
 	{
 		/* continue from last position */
 		start_lsn = slot->data.confirmed_flush;
@@ -757,7 +757,7 @@ output_plugin_error_callback(void *arg)
 	LogicalErrorCallbackState *state = (LogicalErrorCallbackState *) arg;
 
 	/* not all callbacks have an associated LSN  */
-	if (state->report_location != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(state->report_location))
 		errcontext("slot \"%s\", output plugin \"%s\", in the %s callback, associated LSN %X/%08X",
 				   NameStr(state->ctx->slot->data.name),
 				   NameStr(state->ctx->slot->data.plugin),
@@ -1711,7 +1711,7 @@ LogicalIncreaseXminForSlot(XLogRecPtr current_lsn, TransactionId xmin)
 	 * Only increase if the previous values have been applied, otherwise we
 	 * might never end up updating if the receiver acks too slowly.
 	 */
-	else if (slot->candidate_xmin_lsn == InvalidXLogRecPtr)
+	else if (!XLogRecPtrIsValid(slot->candidate_xmin_lsn))
 	{
 		slot->candidate_catalog_xmin = xmin;
 		slot->candidate_xmin_lsn = current_lsn;
@@ -1749,8 +1749,8 @@ LogicalIncreaseRestartDecodingForSlot(XLogRecPtr current_lsn, XLogRecPtr restart
 	slot = MyReplicationSlot;
 
 	Assert(slot != NULL);
-	Assert(restart_lsn != InvalidXLogRecPtr);
-	Assert(current_lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(restart_lsn));
+	Assert(XLogRecPtrIsValid(current_lsn));
 
 	SpinLockAcquire(&slot->mutex);
 
@@ -1779,7 +1779,7 @@ LogicalIncreaseRestartDecodingForSlot(XLogRecPtr current_lsn, XLogRecPtr restart
 	 * might never end up updating if the receiver acks too slowly. A missed
 	 * value here will just cause some extra effort after reconnecting.
 	 */
-	else if (slot->candidate_restart_valid == InvalidXLogRecPtr)
+	else if (!XLogRecPtrIsValid(slot->candidate_restart_valid))
 	{
 		slot->candidate_restart_valid = current_lsn;
 		slot->candidate_restart_lsn = restart_lsn;
@@ -1819,11 +1819,11 @@ LogicalIncreaseRestartDecodingForSlot(XLogRecPtr current_lsn, XLogRecPtr restart
 void
 LogicalConfirmReceivedLocation(XLogRecPtr lsn)
 {
-	Assert(lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(lsn));
 
 	/* Do an unlocked check for candidate_lsn first. */
-	if (MyReplicationSlot->candidate_xmin_lsn != InvalidXLogRecPtr ||
-		MyReplicationSlot->candidate_restart_valid != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(MyReplicationSlot->candidate_xmin_lsn) ||
+		XLogRecPtrIsValid(MyReplicationSlot->candidate_restart_valid))
 	{
 		bool		updated_xmin = false;
 		bool		updated_restart = false;
@@ -1849,7 +1849,7 @@ LogicalConfirmReceivedLocation(XLogRecPtr lsn)
 			MyReplicationSlot->data.confirmed_flush = lsn;
 
 		/* if we're past the location required for bumping xmin, do so */
-		if (MyReplicationSlot->candidate_xmin_lsn != InvalidXLogRecPtr &&
+		if (XLogRecPtrIsValid(MyReplicationSlot->candidate_xmin_lsn) &&
 			MyReplicationSlot->candidate_xmin_lsn <= lsn)
 		{
 			/*
@@ -1871,10 +1871,10 @@ LogicalConfirmReceivedLocation(XLogRecPtr lsn)
 			}
 		}
 
-		if (MyReplicationSlot->candidate_restart_valid != InvalidXLogRecPtr &&
+		if (XLogRecPtrIsValid(MyReplicationSlot->candidate_restart_valid) &&
 			MyReplicationSlot->candidate_restart_valid <= lsn)
 		{
-			Assert(MyReplicationSlot->candidate_restart_lsn != InvalidXLogRecPtr);
+			Assert(XLogRecPtrIsValid(MyReplicationSlot->candidate_restart_lsn));
 
 			MyReplicationSlot->data.restart_lsn = MyReplicationSlot->candidate_restart_lsn;
 			MyReplicationSlot->candidate_restart_lsn = InvalidXLogRecPtr;
@@ -2089,7 +2089,7 @@ LogicalSlotAdvanceAndCheckSnapState(XLogRecPtr moveto,
 	ResourceOwner old_resowner PG_USED_FOR_ASSERTS_ONLY = CurrentResourceOwner;
 	XLogRecPtr	retlsn;
 
-	Assert(moveto != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(moveto));
 
 	if (found_consistent_snapshot)
 		*found_consistent_snapshot = false;
@@ -2163,7 +2163,7 @@ LogicalSlotAdvanceAndCheckSnapState(XLogRecPtr moveto,
 		if (found_consistent_snapshot && DecodingContextReady(ctx))
 			*found_consistent_snapshot = true;
 
-		if (ctx->reader->EndRecPtr != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(ctx->reader->EndRecPtr))
 		{
 			LogicalConfirmReceivedLocation(moveto);
 
diff --git a/src/backend/replication/logical/logicalfuncs.c b/src/backend/replication/logical/logicalfuncs.c
index d78e486bca6..49b2aef3c74 100644
--- a/src/backend/replication/logical/logicalfuncs.c
+++ b/src/backend/replication/logical/logicalfuncs.c
@@ -276,7 +276,7 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin
 			}
 
 			/* check limits */
-			if (upto_lsn != InvalidXLogRecPtr &&
+			if (XLogRecPtrIsValid(upto_lsn) &&
 				upto_lsn <= ctx->reader->EndRecPtr)
 				break;
 			if (upto_nchanges != 0 &&
@@ -289,7 +289,7 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin
 		 * Next time, start where we left off. (Hunting things, the family
 		 * business..)
 		 */
-		if (ctx->reader->EndRecPtr != InvalidXLogRecPtr && confirm)
+		if (XLogRecPtrIsValid(ctx->reader->EndRecPtr) && confirm)
 		{
 			LogicalConfirmReceivedLocation(ctx->reader->EndRecPtr);
 
diff --git a/src/backend/replication/logical/origin.c b/src/backend/replication/logical/origin.c
index bcd5d9aad62..4632aa8115d 100644
--- a/src/backend/replication/logical/origin.c
+++ b/src/backend/replication/logical/origin.c
@@ -984,8 +984,8 @@ replorigin_advance(RepOriginId node,
 		/* initialize new slot */
 		LWLockAcquire(&free_state->lock, LW_EXCLUSIVE);
 		replication_state = free_state;
-		Assert(replication_state->remote_lsn == InvalidXLogRecPtr);
-		Assert(replication_state->local_lsn == InvalidXLogRecPtr);
+		Assert(!XLogRecPtrIsValid(replication_state->remote_lsn));
+		Assert(!XLogRecPtrIsValid(replication_state->local_lsn));
 		replication_state->roident = node;
 	}
 
@@ -1020,7 +1020,7 @@ replorigin_advance(RepOriginId node,
 	 */
 	if (go_backward || replication_state->remote_lsn < remote_commit)
 		replication_state->remote_lsn = remote_commit;
-	if (local_commit != InvalidXLogRecPtr &&
+	if (XLogRecPtrIsValid(local_commit) &&
 		(go_backward || replication_state->local_lsn < local_commit))
 		replication_state->local_lsn = local_commit;
 	LWLockRelease(&replication_state->lock);
@@ -1064,7 +1064,7 @@ replorigin_get_progress(RepOriginId node, bool flush)
 
 	LWLockRelease(ReplicationOriginLock);
 
-	if (flush && local_lsn != InvalidXLogRecPtr)
+	if (flush && XLogRecPtrIsValid(local_lsn))
 		XLogFlush(local_lsn);
 
 	return remote_lsn;
@@ -1197,8 +1197,8 @@ replorigin_session_setup(RepOriginId node, int acquired_by)
 
 		/* initialize new slot */
 		session_replication_state = &replication_states[free_slot];
-		Assert(session_replication_state->remote_lsn == InvalidXLogRecPtr);
-		Assert(session_replication_state->local_lsn == InvalidXLogRecPtr);
+		Assert(!XLogRecPtrIsValid(session_replication_state->remote_lsn));
+		Assert(!XLogRecPtrIsValid(session_replication_state->local_lsn));
 		session_replication_state->roident = node;
 	}
 
@@ -1282,7 +1282,7 @@ replorigin_session_get_progress(bool flush)
 	local_lsn = session_replication_state->local_lsn;
 	LWLockRelease(&session_replication_state->lock);
 
-	if (flush && local_lsn != InvalidXLogRecPtr)
+	if (flush && XLogRecPtrIsValid(local_lsn))
 		XLogFlush(local_lsn);
 
 	return remote_lsn;
@@ -1454,7 +1454,7 @@ pg_replication_origin_session_progress(PG_FUNCTION_ARGS)
 
 	remote_lsn = replorigin_session_get_progress(flush);
 
-	if (remote_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(remote_lsn))
 		PG_RETURN_NULL();
 
 	PG_RETURN_LSN(remote_lsn);
@@ -1543,7 +1543,7 @@ pg_replication_origin_progress(PG_FUNCTION_ARGS)
 
 	remote_lsn = replorigin_get_progress(roident, flush);
 
-	if (remote_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(remote_lsn))
 		PG_RETURN_NULL();
 
 	PG_RETURN_LSN(remote_lsn);
diff --git a/src/backend/replication/logical/proto.c b/src/backend/replication/logical/proto.c
index ed62888764c..f0a913892b9 100644
--- a/src/backend/replication/logical/proto.c
+++ b/src/backend/replication/logical/proto.c
@@ -64,7 +64,7 @@ logicalrep_read_begin(StringInfo in, LogicalRepBeginData *begin_data)
 {
 	/* read fields */
 	begin_data->final_lsn = pq_getmsgint64(in);
-	if (begin_data->final_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(begin_data->final_lsn))
 		elog(ERROR, "final_lsn not set in begin message");
 	begin_data->committime = pq_getmsgint64(in);
 	begin_data->xid = pq_getmsgint(in, 4);
@@ -135,10 +135,10 @@ logicalrep_read_begin_prepare(StringInfo in, LogicalRepPreparedTxnData *begin_da
 {
 	/* read fields */
 	begin_data->prepare_lsn = pq_getmsgint64(in);
-	if (begin_data->prepare_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(begin_data->prepare_lsn))
 		elog(ERROR, "prepare_lsn not set in begin prepare message");
 	begin_data->end_lsn = pq_getmsgint64(in);
-	if (begin_data->end_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(begin_data->end_lsn))
 		elog(ERROR, "end_lsn not set in begin prepare message");
 	begin_data->prepare_time = pq_getmsgint64(in);
 	begin_data->xid = pq_getmsgint(in, 4);
@@ -207,10 +207,10 @@ logicalrep_read_prepare_common(StringInfo in, char *msgtype,
 
 	/* read fields */
 	prepare_data->prepare_lsn = pq_getmsgint64(in);
-	if (prepare_data->prepare_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(prepare_data->prepare_lsn))
 		elog(ERROR, "prepare_lsn is not set in %s message", msgtype);
 	prepare_data->end_lsn = pq_getmsgint64(in);
-	if (prepare_data->end_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(prepare_data->end_lsn))
 		elog(ERROR, "end_lsn is not set in %s message", msgtype);
 	prepare_data->prepare_time = pq_getmsgint64(in);
 	prepare_data->xid = pq_getmsgint(in, 4);
@@ -274,10 +274,10 @@ logicalrep_read_commit_prepared(StringInfo in, LogicalRepCommitPreparedTxnData *
 
 	/* read fields */
 	prepare_data->commit_lsn = pq_getmsgint64(in);
-	if (prepare_data->commit_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(prepare_data->commit_lsn))
 		elog(ERROR, "commit_lsn is not set in commit prepared message");
 	prepare_data->end_lsn = pq_getmsgint64(in);
-	if (prepare_data->end_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(prepare_data->end_lsn))
 		elog(ERROR, "end_lsn is not set in commit prepared message");
 	prepare_data->commit_time = pq_getmsgint64(in);
 	prepare_data->xid = pq_getmsgint(in, 4);
@@ -333,10 +333,10 @@ logicalrep_read_rollback_prepared(StringInfo in,
 
 	/* read fields */
 	rollback_data->prepare_end_lsn = pq_getmsgint64(in);
-	if (rollback_data->prepare_end_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(rollback_data->prepare_end_lsn))
 		elog(ERROR, "prepare_end_lsn is not set in rollback prepared message");
 	rollback_data->rollback_end_lsn = pq_getmsgint64(in);
-	if (rollback_data->rollback_end_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(rollback_data->rollback_end_lsn))
 		elog(ERROR, "rollback_end_lsn is not set in rollback prepared message");
 	rollback_data->prepare_time = pq_getmsgint64(in);
 	rollback_data->rollback_time = pq_getmsgint64(in);
diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c
index b57aef9916d..eb6a84554b7 100644
--- a/src/backend/replication/logical/reorderbuffer.c
+++ b/src/backend/replication/logical/reorderbuffer.c
@@ -701,7 +701,7 @@ ReorderBufferTXNByXid(ReorderBuffer *rb, TransactionId xid, bool create,
 	{
 		/* initialize the new entry, if creation was requested */
 		Assert(ent != NULL);
-		Assert(lsn != InvalidXLogRecPtr);
+		Assert(XLogRecPtrIsValid(lsn));
 
 		ent->txn = ReorderBufferAllocTXN(rb);
 		ent->txn->xid = xid;
@@ -849,7 +849,7 @@ ReorderBufferQueueChange(ReorderBuffer *rb, TransactionId xid, XLogRecPtr lsn,
 	change->lsn = lsn;
 	change->txn = txn;
 
-	Assert(InvalidXLogRecPtr != lsn);
+	Assert(XLogRecPtrIsValid(lsn));
 	dlist_push_tail(&txn->changes, &change->node);
 	txn->nentries++;
 	txn->nentries_mem++;
@@ -966,14 +966,14 @@ AssertTXNLsnOrder(ReorderBuffer *rb)
 													iter.cur);
 
 		/* start LSN must be set */
-		Assert(cur_txn->first_lsn != InvalidXLogRecPtr);
+		Assert(XLogRecPtrIsValid(cur_txn->first_lsn));
 
 		/* If there is an end LSN, it must be higher than start LSN */
-		if (cur_txn->end_lsn != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(cur_txn->end_lsn))
 			Assert(cur_txn->first_lsn <= cur_txn->end_lsn);
 
 		/* Current initial LSN must be strictly higher than previous */
-		if (prev_first_lsn != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(prev_first_lsn))
 			Assert(prev_first_lsn < cur_txn->first_lsn);
 
 		/* known-as-subtxn txns must not be listed */
@@ -990,10 +990,10 @@ AssertTXNLsnOrder(ReorderBuffer *rb)
 
 		/* base snapshot (and its LSN) must be set */
 		Assert(cur_txn->base_snapshot != NULL);
-		Assert(cur_txn->base_snapshot_lsn != InvalidXLogRecPtr);
+		Assert(XLogRecPtrIsValid(cur_txn->base_snapshot_lsn));
 
 		/* current LSN must be strictly higher than previous */
-		if (prev_base_snap_lsn != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(prev_base_snap_lsn))
 			Assert(prev_base_snap_lsn < cur_txn->base_snapshot_lsn);
 
 		/* known-as-subtxn txns must not be listed */
@@ -1022,11 +1022,11 @@ AssertChangeLsnOrder(ReorderBufferTXN *txn)
 
 		cur_change = dlist_container(ReorderBufferChange, node, iter.cur);
 
-		Assert(txn->first_lsn != InvalidXLogRecPtr);
-		Assert(cur_change->lsn != InvalidXLogRecPtr);
+		Assert(XLogRecPtrIsValid(txn->first_lsn));
+		Assert(XLogRecPtrIsValid(cur_change->lsn));
 		Assert(txn->first_lsn <= cur_change->lsn);
 
-		if (txn->end_lsn != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(txn->end_lsn))
 			Assert(cur_change->lsn <= txn->end_lsn);
 
 		Assert(prev_lsn <= cur_change->lsn);
@@ -1053,7 +1053,7 @@ ReorderBufferGetOldestTXN(ReorderBuffer *rb)
 	txn = dlist_head_element(ReorderBufferTXN, node, &rb->toplevel_by_lsn);
 
 	Assert(!rbtxn_is_known_subxact(txn));
-	Assert(txn->first_lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(txn->first_lsn));
 	return txn;
 }
 
@@ -2276,7 +2276,7 @@ ReorderBufferProcessTXN(ReorderBuffer *rb, ReorderBufferTXN *txn,
 			 * We can't call start stream callback before processing first
 			 * change.
 			 */
-			if (prev_lsn == InvalidXLogRecPtr)
+			if (!XLogRecPtrIsValid(prev_lsn))
 			{
 				if (streaming)
 				{
@@ -2291,7 +2291,7 @@ ReorderBufferProcessTXN(ReorderBuffer *rb, ReorderBufferTXN *txn,
 			 * subtransactions. The changes may have the same LSN due to
 			 * MULTI_INSERT xlog records.
 			 */
-			Assert(prev_lsn == InvalidXLogRecPtr || prev_lsn <= change->lsn);
+			Assert(!XLogRecPtrIsValid(prev_lsn) || prev_lsn <= change->lsn);
 
 			prev_lsn = change->lsn;
 
@@ -2975,7 +2975,7 @@ ReorderBufferPrepare(ReorderBuffer *rb, TransactionId xid,
 	 * have been updated in it by now.
 	 */
 	Assert((txn->txn_flags & RBTXN_PREPARE_STATUS_MASK) == RBTXN_IS_PREPARED);
-	Assert(txn->final_lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(txn->final_lsn));
 
 	txn->gid = pstrdup(gid);
 
@@ -3041,7 +3041,7 @@ ReorderBufferFinishPrepared(ReorderBuffer *rb, TransactionId xid,
 		 */
 		Assert((txn->txn_flags & RBTXN_PREPARE_STATUS_MASK) ==
 			   (RBTXN_IS_PREPARED | RBTXN_SKIPPED_PREPARE));
-		Assert(txn->final_lsn != InvalidXLogRecPtr);
+		Assert(XLogRecPtrIsValid(txn->final_lsn));
 
 		/*
 		 * By this time the txn has the prepare record information and it is
@@ -4552,8 +4552,8 @@ ReorderBufferRestoreChanges(ReorderBuffer *rb, ReorderBufferTXN *txn,
 	dlist_mutable_iter cleanup_iter;
 	File	   *fd = &file->vfd;
 
-	Assert(txn->first_lsn != InvalidXLogRecPtr);
-	Assert(txn->final_lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(txn->first_lsn));
+	Assert(XLogRecPtrIsValid(txn->final_lsn));
 
 	/* free current entries, so we have memory for more */
 	dlist_foreach_modify(cleanup_iter, &txn->changes)
@@ -4860,8 +4860,8 @@ ReorderBufferRestoreCleanup(ReorderBuffer *rb, ReorderBufferTXN *txn)
 	XLogSegNo	cur;
 	XLogSegNo	last;
 
-	Assert(txn->first_lsn != InvalidXLogRecPtr);
-	Assert(txn->final_lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(txn->first_lsn));
+	Assert(XLogRecPtrIsValid(txn->final_lsn));
 
 	XLByteToSeg(txn->first_lsn, first, wal_segment_size);
 	XLByteToSeg(txn->final_lsn, last, wal_segment_size);
diff --git a/src/backend/replication/logical/snapbuild.c b/src/backend/replication/logical/snapbuild.c
index 98ddee20929..6e18baa33cb 100644
--- a/src/backend/replication/logical/snapbuild.c
+++ b/src/backend/replication/logical/snapbuild.c
@@ -1210,7 +1210,7 @@ SnapBuildProcessRunningXacts(SnapBuild *builder, XLogRecPtr lsn, xl_running_xact
 	 * oldest ongoing txn might have started when we didn't yet serialize
 	 * anything because we hadn't reached a consistent state yet.
 	 */
-	if (txn != NULL && txn->restart_decoding_lsn != InvalidXLogRecPtr)
+	if (txn != NULL && XLogRecPtrIsValid(txn->restart_decoding_lsn))
 		LogicalIncreaseRestartDecodingForSlot(lsn, txn->restart_decoding_lsn);
 
 	/*
@@ -1218,8 +1218,8 @@ SnapBuildProcessRunningXacts(SnapBuild *builder, XLogRecPtr lsn, xl_running_xact
 	 * we have one.
 	 */
 	else if (txn == NULL &&
-			 builder->reorder->current_restart_decoding_lsn != InvalidXLogRecPtr &&
-			 builder->last_serialized_snapshot != InvalidXLogRecPtr)
+			 XLogRecPtrIsValid(builder->reorder->current_restart_decoding_lsn) &&
+			 XLogRecPtrIsValid(builder->last_serialized_snapshot))
 		LogicalIncreaseRestartDecodingForSlot(lsn,
 											  builder->last_serialized_snapshot);
 }
@@ -1293,7 +1293,7 @@ SnapBuildFindSnapshot(SnapBuild *builder, XLogRecPtr lsn, xl_running_xacts *runn
 	 */
 	if (running->oldestRunningXid == running->nextXid)
 	{
-		if (builder->start_decoding_at == InvalidXLogRecPtr ||
+		if (!XLogRecPtrIsValid(builder->start_decoding_at) ||
 			builder->start_decoding_at <= lsn)
 			/* can decode everything after this */
 			builder->start_decoding_at = lsn + 1;
@@ -1509,8 +1509,8 @@ SnapBuildSerialize(SnapBuild *builder, XLogRecPtr lsn)
 	struct stat stat_buf;
 	Size		sz;
 
-	Assert(lsn != InvalidXLogRecPtr);
-	Assert(builder->last_serialized_snapshot == InvalidXLogRecPtr ||
+	Assert(XLogRecPtrIsValid(lsn));
+	Assert(!XLogRecPtrIsValid(builder->last_serialized_snapshot) ||
 		   builder->last_serialized_snapshot <= lsn);
 
 	/*
@@ -2029,7 +2029,7 @@ CheckPointSnapBuild(void)
 		lsn = ((uint64) hi) << 32 | lo;
 
 		/* check whether we still need it */
-		if (lsn < cutoff || cutoff == InvalidXLogRecPtr)
+		if (lsn < cutoff || !XLogRecPtrIsValid(cutoff))
 		{
 			elog(DEBUG1, "removing snapbuild snapshot %s", path);
 
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index 0cb93dc90f2..1ec1e997b27 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -1270,15 +1270,15 @@ ReplicationSlotsComputeRequiredLSN(void)
 		 */
 		if (persistency == RS_PERSISTENT)
 		{
-			if (last_saved_restart_lsn != InvalidXLogRecPtr &&
+			if (XLogRecPtrIsValid(last_saved_restart_lsn) &&
 				restart_lsn > last_saved_restart_lsn)
 			{
 				restart_lsn = last_saved_restart_lsn;
 			}
 		}
 
-		if (restart_lsn != InvalidXLogRecPtr &&
-			(min_required == InvalidXLogRecPtr ||
+		if (XLogRecPtrIsValid(restart_lsn) &&
+			(!XLogRecPtrIsValid(min_required) ||
 			 restart_lsn < min_required))
 			min_required = restart_lsn;
 	}
@@ -1350,17 +1350,17 @@ ReplicationSlotsComputeLogicalRestartLSN(void)
 		 */
 		if (persistency == RS_PERSISTENT)
 		{
-			if (last_saved_restart_lsn != InvalidXLogRecPtr &&
+			if (XLogRecPtrIsValid(last_saved_restart_lsn) &&
 				restart_lsn > last_saved_restart_lsn)
 			{
 				restart_lsn = last_saved_restart_lsn;
 			}
 		}
 
-		if (restart_lsn == InvalidXLogRecPtr)
+		if (!XLogRecPtrIsValid(restart_lsn))
 			continue;
 
-		if (result == InvalidXLogRecPtr ||
+		if (!XLogRecPtrIsValid(result) ||
 			restart_lsn < result)
 			result = restart_lsn;
 	}
@@ -1573,8 +1573,8 @@ ReplicationSlotReserveWal(void)
 	ReplicationSlot *slot = MyReplicationSlot;
 
 	Assert(slot != NULL);
-	Assert(slot->data.restart_lsn == InvalidXLogRecPtr);
-	Assert(slot->last_saved_restart_lsn == InvalidXLogRecPtr);
+	Assert(!XLogRecPtrIsValid(slot->data.restart_lsn));
+	Assert(!XLogRecPtrIsValid(slot->last_saved_restart_lsn));
 
 	/*
 	 * The replication slot mechanism is used to prevent removal of required
@@ -1754,7 +1754,7 @@ DetermineSlotInvalidationCause(uint32 possible_causes, ReplicationSlot *s,
 	{
 		XLogRecPtr	restart_lsn = s->data.restart_lsn;
 
-		if (restart_lsn != InvalidXLogRecPtr &&
+		if (XLogRecPtrIsValid(restart_lsn) &&
 			restart_lsn < oldestLSN)
 			return RS_INVAL_WAL_REMOVED;
 	}
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 5aecd5c6a50..0478fc9c977 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -308,12 +308,12 @@ pg_get_replication_slots(PG_FUNCTION_ARGS)
 		else
 			nulls[i++] = true;
 
-		if (slot_contents.data.restart_lsn != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(slot_contents.data.restart_lsn))
 			values[i++] = LSNGetDatum(slot_contents.data.restart_lsn);
 		else
 			nulls[i++] = true;
 
-		if (slot_contents.data.confirmed_flush != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(slot_contents.data.confirmed_flush))
 			values[i++] = LSNGetDatum(slot_contents.data.confirmed_flush);
 		else
 			nulls[i++] = true;
@@ -467,7 +467,7 @@ pg_physical_replication_slot_advance(XLogRecPtr moveto)
 	XLogRecPtr	startlsn = MyReplicationSlot->data.restart_lsn;
 	XLogRecPtr	retlsn = startlsn;
 
-	Assert(moveto != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(moveto));
 
 	if (startlsn < moveto)
 	{
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index b6dfb230d0d..4a678e60b74 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -2397,7 +2397,7 @@ PhysicalConfirmReceivedLocation(XLogRecPtr lsn)
 	bool		changed = false;
 	ReplicationSlot *slot = MyReplicationSlot;
 
-	Assert(lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(lsn));
 	SpinLockAcquire(&slot->mutex);
 	if (slot->data.restart_lsn != lsn)
 	{
@@ -2519,7 +2519,7 @@ ProcessStandbyReplyMessage(void)
 	/*
 	 * Advance our local xmin horizon when the client confirmed a flush.
 	 */
-	if (MyReplicationSlot && flushPtr != InvalidXLogRecPtr)
+	if (MyReplicationSlot && XLogRecPtrIsValid(flushPtr))
 	{
 		if (SlotIsLogical(MyReplicationSlot))
 			LogicalConfirmReceivedLocation(flushPtr);
@@ -3536,7 +3536,7 @@ XLogSendLogical(void)
 	 * If first time through in this session, initialize flushPtr.  Otherwise,
 	 * we only need to update flushPtr if EndRecPtr is past it.
 	 */
-	if (flushPtr == InvalidXLogRecPtr ||
+	if (!XLogRecPtrIsValid(flushPtr) ||
 		logical_decoding_ctx->reader->EndRecPtr >= flushPtr)
 	{
 		/*
diff --git a/src/bin/pg_basebackup/pg_receivewal.c b/src/bin/pg_basebackup/pg_receivewal.c
index 3e6f4a7fc48..46e553dce4b 100644
--- a/src/bin/pg_basebackup/pg_receivewal.c
+++ b/src/bin/pg_basebackup/pg_receivewal.c
@@ -535,7 +535,7 @@ StreamLog(void)
 	 * Figure out where to start streaming.  First scan the local directory.
 	 */
 	stream.startpos = FindStreamingStart(&stream.timeline);
-	if (stream.startpos == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(stream.startpos))
 	{
 		/*
 		 * Try to get the starting point from the slot if any.  This is
@@ -556,14 +556,14 @@ StreamLog(void)
 		 * If it the starting point is still not known, use the current WAL
 		 * flush value as last resort.
 		 */
-		if (stream.startpos == InvalidXLogRecPtr)
+		if (!XLogRecPtrIsValid(stream.startpos))
 		{
 			stream.startpos = serverpos;
 			stream.timeline = servertli;
 		}
 	}
 
-	Assert(stream.startpos != InvalidXLogRecPtr &&
+	Assert(XLogRecPtrIsValid(stream.startpos) &&
 		   stream.timeline != 0);
 
 	/*
diff --git a/src/bin/pg_basebackup/pg_recvlogical.c b/src/bin/pg_basebackup/pg_recvlogical.c
index 6739784a993..14ad1504678 100644
--- a/src/bin/pg_basebackup/pg_recvlogical.c
+++ b/src/bin/pg_basebackup/pg_recvlogical.c
@@ -482,7 +482,7 @@ StreamLogicalLog(void)
 			}
 			replyRequested = copybuf[pos];
 
-			if (endpos != InvalidXLogRecPtr && walEnd >= endpos)
+			if (XLogRecPtrIsValid(endpos) && walEnd >= endpos)
 			{
 				/*
 				 * If there's nothing to read on the socket until a keepalive
@@ -535,7 +535,7 @@ StreamLogicalLog(void)
 		/* Extract WAL location for this block */
 		cur_record_lsn = fe_recvint64(&copybuf[1]);
 
-		if (endpos != InvalidXLogRecPtr && cur_record_lsn > endpos)
+		if (XLogRecPtrIsValid(endpos) && cur_record_lsn > endpos)
 		{
 			/*
 			 * We've read past our endpoint, so prepare to go away being
@@ -583,7 +583,7 @@ StreamLogicalLog(void)
 			goto error;
 		}
 
-		if (endpos != InvalidXLogRecPtr && cur_record_lsn == endpos)
+		if (XLogRecPtrIsValid(endpos) && cur_record_lsn == endpos)
 		{
 			/* endpos was exactly the record we just processed, we're done */
 			if (!flushAndSendFeedback(conn, &now))
@@ -913,14 +913,14 @@ main(int argc, char **argv)
 		exit(1);
 	}
 
-	if (startpos != InvalidXLogRecPtr && (do_create_slot || do_drop_slot))
+	if (XLogRecPtrIsValid(startpos) && (do_create_slot || do_drop_slot))
 	{
 		pg_log_error("cannot use --create-slot or --drop-slot together with --startpos");
 		pg_log_error_hint("Try \"%s --help\" for more information.", progname);
 		exit(1);
 	}
 
-	if (endpos != InvalidXLogRecPtr && !do_start_slot)
+	if (XLogRecPtrIsValid(endpos) && !do_start_slot)
 	{
 		pg_log_error("--endpos may only be specified with --start");
 		pg_log_error_hint("Try \"%s --help\" for more information.", progname);
diff --git a/src/bin/pg_waldump/pg_waldump.c b/src/bin/pg_waldump/pg_waldump.c
index 19cf5461eac..c6d6ba79e44 100644
--- a/src/bin/pg_waldump/pg_waldump.c
+++ b/src/bin/pg_waldump/pg_waldump.c
@@ -393,7 +393,7 @@ WALDumpReadPage(XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen,
 	int			count = XLOG_BLCKSZ;
 	WALReadError errinfo;
 
-	if (private->endptr != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(private->endptr))
 	{
 		if (targetPagePtr + XLOG_BLCKSZ <= private->endptr)
 			count = XLOG_BLCKSZ;
@@ -1213,7 +1213,7 @@ main(int argc, char **argv)
 	/* first find a valid recptr to start from */
 	first_record = XLogFindNextRecord(xlogreader_state, private.startptr);
 
-	if (first_record == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(first_record))
 		pg_fatal("could not find a valid record after %X/%08X",
 				 LSN_FORMAT_ARGS(private.startptr));
 
diff --git a/src/include/access/xlogdefs.h b/src/include/access/xlogdefs.h
index 2589a21083b..06fcfeeb9d0 100644
--- a/src/include/access/xlogdefs.h
+++ b/src/include/access/xlogdefs.h
@@ -41,7 +41,7 @@ PG_DEPRECATED("use XLogRecPtrIsValid() instead")
 static inline bool
 XLogRecPtrIsInvalid(XLogRecPtr ptr)
 {
-	return ptr == InvalidXLogRecPtr;
+	return !XLogRecPtrIsValid(ptr);
 }
 
 /*
-- 
2.34.1

v5-0004-Replace-literal-0-comparisons-on-XLogRecPtr-with-.patchtext/x-diff; charset=us-asciiDownload
From 8a57bb542ad062c717ebd0a5adc4ffc8968ff437 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Wed, 29 Oct 2025 18:46:28 +0000
Subject: [PATCH v5 4/4] Replace literal 0 comparisons on XLogRecPtr with
 XLogRecPtrIsValid()

This commit ensures the XLogRecPtrIsValid() macro is used instead of direct
literal 0 comparisons on XLogRecPtr.
---
 src/backend/access/transam/xlogfuncs.c     | 4 ++--
 src/backend/replication/walreceiverfuncs.c | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)
  42.3% src/backend/access/transam/
  57.6% src/backend/replication/

diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index 8c3090165f0..3e45fce43ed 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -341,7 +341,7 @@ pg_last_wal_receive_lsn(PG_FUNCTION_ARGS)
 
 	recptr = GetWalRcvFlushRecPtr(NULL, NULL);
 
-	if (recptr == 0)
+	if (!XLogRecPtrIsValid(recptr))
 		PG_RETURN_NULL();
 
 	PG_RETURN_LSN(recptr);
@@ -360,7 +360,7 @@ pg_last_wal_replay_lsn(PG_FUNCTION_ARGS)
 
 	recptr = GetXLogReplayRecPtr(NULL);
 
-	if (recptr == 0)
+	if (!XLogRecPtrIsValid(recptr))
 		PG_RETURN_NULL();
 
 	PG_RETURN_LSN(recptr);
diff --git a/src/backend/replication/walreceiverfuncs.c b/src/backend/replication/walreceiverfuncs.c
index 6a693d854c4..822645748a7 100644
--- a/src/backend/replication/walreceiverfuncs.c
+++ b/src/backend/replication/walreceiverfuncs.c
@@ -315,7 +315,7 @@ RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, const char *conninfo,
 	 * If this is the first startup of walreceiver (on this timeline),
 	 * initialize flushedUpto and latestChunkStart to the starting point.
 	 */
-	if (walrcv->receiveStart == 0 || walrcv->receivedTLI != tli)
+	if (!XLogRecPtrIsValid(walrcv->receiveStart) || walrcv->receivedTLI != tli)
 	{
 		walrcv->flushedUpto = recptr;
 		walrcv->receivedTLI = tli;
-- 
2.34.1

#18Álvaro Herrera
alvherre@kurilemu.de
In reply to: Bertrand Drouvot (#17)
Re: Consistently use the XLogRecPtrIsInvalid() macro

On 2025-Nov-06, Bertrand Drouvot wrote:

Subject: [PATCH v5 1/4] Introduce XLogRecPtrIsValid() and replace
XLogRecPtrIsInvalid() calls

XLogRecPtrIsInvalid() is inconsistent with the affirmative form of other
*IsValid() macros and leads to awkward double negative.

This commit introduces XLogRecPtrIsValid() and replace all the
XLogRecPtrIsInvalid() calls.

It also adds a comment mentioning that new code should use XLogRecPtrIsValid()
instead of XLogRecPtrIsInvalid() and that XLogRecPtrIsInvalid() could be
deprecated in the future.

I think we should do this in two steps. First, introduce
XLogRecPtrIsValid(), don't use it anywhere, backpatch this one. This
would alleviate potential backpatching pains when using the new macro in
future bugfixes. Second, change calls of the old function to the new
one, no backpatch.

From 22f02ca0618d9f2e34de8fa084127bf500d75603 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Mon, 3 Nov 2025 06:33:01 +0000
Subject: [PATCH v5 2/4] Introduce PG_DEPRECATED() and deprecate
XLogRecPtrIsInvalid()

The uppercase name looks a bit ugly. We use lowercase for other uses of
__attribute__, e.g. pg_attribute_aligned(). Also, probably add
"attribute" to the name, for consistency with those.

--
Álvaro Herrera Breisgau, Deutschland — https://www.EnterpriseDB.com/

#19Bertrand Drouvot
bertranddrouvot.pg@gmail.com
In reply to: Álvaro Herrera (#18)
5 attachment(s)
Re: Consistently use the XLogRecPtrIsInvalid() macro

Hi,

On Thu, Nov 06, 2025 at 10:06:13AM +0100, �lvaro Herrera wrote:

On 2025-Nov-06, Bertrand Drouvot wrote:

Subject: [PATCH v5 1/4] Introduce XLogRecPtrIsValid() and replace
XLogRecPtrIsInvalid() calls

XLogRecPtrIsInvalid() is inconsistent with the affirmative form of other
*IsValid() macros and leads to awkward double negative.

This commit introduces XLogRecPtrIsValid() and replace all the
XLogRecPtrIsInvalid() calls.

It also adds a comment mentioning that new code should use XLogRecPtrIsValid()
instead of XLogRecPtrIsInvalid() and that XLogRecPtrIsInvalid() could be
deprecated in the future.

I think we should do this in two steps. First, introduce
XLogRecPtrIsValid(), don't use it anywhere, backpatch this one. This
would alleviate potential backpatching pains when using the new macro in
future bugfixes.

I see, I would have introduced XLogRecPtrIsInvalid() on the back branches only
if there is a need to (a bugfix that would make use of it). But yeah, I agree
that would add extra "unnecessary" work, so done as you suggested in the
attached. I checked that 0001 apply on the [14-18]_STABLE branches successfully.

The uppercase name looks a bit ugly. We use lowercase for other uses of
__attribute__, e.g. pg_attribute_aligned(). Also, probably add
"attribute" to the name, for consistency with those.

Right, replaced by pg_attribute_deprecated() in the attached.

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

Attachments:

v6-0001-Introduce-XLogRecPtrIsValid.patchtext/x-diff; charset=us-asciiDownload
From 58f43ec0fbdc02a43f3f070b301ab0a264fa1013 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Thu, 6 Nov 2025 13:38:19 +0000
Subject: [PATCH v6 1/5] Introduce XLogRecPtrIsValid()

XLogRecPtrIsInvalid() is inconsistent with the affirmative form of other
*IsValid() macros and leads to awkward double negative.

This commit introduces XLogRecPtrIsValid() and adds a comment mentioning that
new code should use XLogRecPtrIsValid() instead of XLogRecPtrIsInvalid() and
that XLogRecPtrIsInvalid() could be deprecated in the future.
---
 src/include/access/xlogdefs.h | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)
 100.0% src/include/access/

diff --git a/src/include/access/xlogdefs.h b/src/include/access/xlogdefs.h
index 2397fb24115..b16b2a1c8a3 100644
--- a/src/include/access/xlogdefs.h
+++ b/src/include/access/xlogdefs.h
@@ -26,8 +26,16 @@ typedef uint64 XLogRecPtr;
  * record can begin at zero.
  */
 #define InvalidXLogRecPtr	0
-#define XLogRecPtrIsInvalid(r)	((r) == InvalidXLogRecPtr)
+#define XLogRecPtrIsValid(r) ((r) != InvalidXLogRecPtr)
 
+/*
+ * New code should use XLogRecPtrIsValid() instead of XLogRecPtrIsInvalid()
+ * for consistency with the affirmative form of other *IsValid() macros and to
+ * avoid awkward double negative.
+ * This macro is retained for convenience of third-party code but could
+ * be deprecated in the future.
+ */
+#define XLogRecPtrIsInvalid(r)	((r) == InvalidXLogRecPtr)
 /*
  * First LSN to use for "fake" LSNs.
  *
-- 
2.34.1

v6-0002-Replace-XLogRecPtrIsInvalid-calls-by-XLogRecPtrIs.patchtext/x-diff; charset=us-asciiDownload
From ed3435ecbd8532126b5342476afaab159241b910 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Wed, 29 Oct 2025 10:34:03 +0000
Subject: [PATCH v6 2/5] Replace XLogRecPtrIsInvalid() calls by
 XLogRecPtrIsValid()

Now that commit <id> has introduced XLogRecPtrIsValid() and mentioned that
XLogRecPtrIsInvalid() could be deprecated in the future, replace XLogRecPtrIsInvalid()
calls by XLogRecPtrIsValid().
---
 contrib/pg_walinspect/pg_walinspect.c         |  4 +--
 src/backend/access/gist/gist.c                |  4 +--
 src/backend/access/gist/gistget.c             |  4 +--
 src/backend/access/gist/gistutil.c            |  2 +-
 src/backend/access/heap/visibilitymap.c       |  4 +--
 src/backend/access/transam/clog.c             |  5 ++--
 src/backend/access/transam/slru.c             |  2 +-
 src/backend/access/transam/timeline.c         |  4 +--
 src/backend/access/transam/twophase.c         |  4 +--
 src/backend/access/transam/xlog.c             | 30 +++++++++----------
 src/backend/access/transam/xlogbackup.c       |  4 +--
 src/backend/access/transam/xlogreader.c       |  6 ++--
 src/backend/access/transam/xlogrecovery.c     | 12 ++++----
 src/backend/access/transam/xlogwait.c         |  2 +-
 src/backend/backup/backup_manifest.c          |  4 +--
 src/backend/backup/basebackup_incremental.c   |  2 +-
 src/backend/backup/walsummary.c               |  8 ++---
 src/backend/commands/subscriptioncmds.c       |  6 ++--
 src/backend/postmaster/walsummarizer.c        | 18 +++++------
 .../replication/logical/applyparallelworker.c |  4 +--
 src/backend/replication/logical/launcher.c    |  4 +--
 src/backend/replication/logical/logical.c     |  2 +-
 .../replication/logical/logicalfuncs.c        |  2 +-
 src/backend/replication/logical/slotsync.c    |  6 ++--
 src/backend/replication/logical/worker.c      | 16 +++++-----
 src/backend/replication/slot.c                | 10 +++----
 src/backend/replication/slotfuncs.c           | 16 +++++-----
 src/backend/replication/syncrep.c             | 10 +++----
 src/backend/replication/walreceiver.c         |  8 ++---
 src/backend/replication/walsender.c           | 22 +++++++-------
 src/backend/storage/buffer/bufmgr.c           |  2 +-
 src/bin/pg_basebackup/pg_receivewal.c         |  2 +-
 src/bin/pg_basebackup/pg_recvlogical.c        |  2 +-
 src/bin/pg_rewind/pg_rewind.c                 |  4 +--
 src/bin/pg_waldump/pg_waldump.c               | 10 +++----
 35 files changed, 123 insertions(+), 122 deletions(-)
   4.3% src/backend/access/gist/
  28.4% src/backend/access/transam/
   6.6% src/backend/backup/
   7.7% src/backend/postmaster/
  14.2% src/backend/replication/logical/
  26.7% src/backend/replication/
   4.1% src/backend/
   3.8% src/bin/pg_waldump/

diff --git a/contrib/pg_walinspect/pg_walinspect.c b/contrib/pg_walinspect/pg_walinspect.c
index 501cea8fc1a..3c5e4a856a7 100644
--- a/contrib/pg_walinspect/pg_walinspect.c
+++ b/contrib/pg_walinspect/pg_walinspect.c
@@ -83,7 +83,7 @@ GetCurrentLSN(void)
 	else
 		curr_lsn = GetXLogReplayRecPtr(NULL);
 
-	Assert(!XLogRecPtrIsInvalid(curr_lsn));
+	Assert(XLogRecPtrIsValid(curr_lsn));
 
 	return curr_lsn;
 }
@@ -127,7 +127,7 @@ InitXLogReaderState(XLogRecPtr lsn)
 	/* first find a valid recptr to start from */
 	first_valid_record = XLogFindNextRecord(xlogreader, lsn);
 
-	if (XLogRecPtrIsInvalid(first_valid_record))
+	if (!XLogRecPtrIsValid(first_valid_record))
 		ereport(ERROR,
 				errmsg("could not find a valid record after %X/%08X",
 					   LSN_FORMAT_ARGS(lsn)));
diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c
index 5213cd71e97..3fb1a1285c5 100644
--- a/src/backend/access/gist/gist.c
+++ b/src/backend/access/gist/gist.c
@@ -682,7 +682,7 @@ gistdoinsert(Relation r, IndexTuple itup, Size freespace,
 			state.stack = stack = stack->parent;
 		}
 
-		if (XLogRecPtrIsInvalid(stack->lsn))
+		if (!XLogRecPtrIsValid(stack->lsn))
 			stack->buffer = ReadBuffer(state.r, stack->blkno);
 
 		/*
@@ -698,7 +698,7 @@ gistdoinsert(Relation r, IndexTuple itup, Size freespace,
 		stack->page = BufferGetPage(stack->buffer);
 		stack->lsn = xlocked ?
 			PageGetLSN(stack->page) : BufferGetLSNAtomic(stack->buffer);
-		Assert(!RelationNeedsWAL(state.r) || !XLogRecPtrIsInvalid(stack->lsn));
+		Assert(!RelationNeedsWAL(state.r) || XLogRecPtrIsValid(stack->lsn));
 
 		/*
 		 * If this page was split but the downlink was never inserted to the
diff --git a/src/backend/access/gist/gistget.c b/src/backend/access/gist/gistget.c
index 387d9972345..9ba45acfff3 100644
--- a/src/backend/access/gist/gistget.c
+++ b/src/backend/access/gist/gistget.c
@@ -46,7 +46,7 @@ gistkillitems(IndexScanDesc scan)
 	bool		killedsomething = false;
 
 	Assert(so->curBlkno != InvalidBlockNumber);
-	Assert(!XLogRecPtrIsInvalid(so->curPageLSN));
+	Assert(XLogRecPtrIsValid(so->curPageLSN));
 	Assert(so->killedItems != NULL);
 
 	buffer = ReadBuffer(scan->indexRelation, so->curBlkno);
@@ -353,7 +353,7 @@ gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem,
 	 * parentlsn < nsn), or if the system crashed after a page split but
 	 * before the downlink was inserted into the parent.
 	 */
-	if (!XLogRecPtrIsInvalid(pageItem->data.parentlsn) &&
+	if (XLogRecPtrIsValid(pageItem->data.parentlsn) &&
 		(GistFollowRight(page) ||
 		 pageItem->data.parentlsn < GistPageGetNSN(page)) &&
 		opaque->rightlink != InvalidBlockNumber /* sanity check */ )
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index 98b79608341..75272827837 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -1040,7 +1040,7 @@ gistGetFakeLSN(Relation rel)
 		Assert(!RelationNeedsWAL(rel));
 
 		/* No need for an actual record if we already have a distinct LSN */
-		if (!XLogRecPtrIsInvalid(lastlsn) && lastlsn == currlsn)
+		if (XLogRecPtrIsValid(lastlsn) && lastlsn == currlsn)
 			currlsn = gistXLogAssignLSN();
 
 		lastlsn = currlsn;
diff --git a/src/backend/access/heap/visibilitymap.c b/src/backend/access/heap/visibilitymap.c
index 2f5e61e2392..d14588e92ae 100644
--- a/src/backend/access/heap/visibilitymap.c
+++ b/src/backend/access/heap/visibilitymap.c
@@ -260,7 +260,7 @@ visibilitymap_set(Relation rel, BlockNumber heapBlk, Buffer heapBuf,
 		 flags, RelationGetRelationName(rel), heapBlk);
 #endif
 
-	Assert(InRecovery || XLogRecPtrIsInvalid(recptr));
+	Assert(InRecovery || !XLogRecPtrIsValid(recptr));
 	Assert(InRecovery || PageIsAllVisible(BufferGetPage(heapBuf)));
 	Assert((flags & VISIBILITYMAP_VALID_BITS) == flags);
 
@@ -292,7 +292,7 @@ visibilitymap_set(Relation rel, BlockNumber heapBlk, Buffer heapBuf,
 
 		if (RelationNeedsWAL(rel))
 		{
-			if (XLogRecPtrIsInvalid(recptr))
+			if (!XLogRecPtrIsValid(recptr))
 			{
 				Assert(!InRecovery);
 				recptr = log_heap_visible(rel, heapBuf, vmBuf, cutoff_xid, flags);
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index e80fbe109cf..ea43b432daf 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -381,7 +381,8 @@ TransactionIdSetPageStatusInternal(TransactionId xid, int nsubxids,
 	 * write-busy, since we don't care if the update reaches disk sooner than
 	 * we think.
 	 */
-	slotno = SimpleLruReadPage(XactCtl, pageno, XLogRecPtrIsInvalid(lsn), xid);
+	slotno = SimpleLruReadPage(XactCtl, pageno, !XLogRecPtrIsValid(lsn),
+							   xid);
 
 	/*
 	 * Set the main transaction id, if any.
@@ -705,7 +706,7 @@ TransactionIdSetStatusBit(TransactionId xid, XidStatus status, XLogRecPtr lsn, i
 	 * recovery. After recovery completes the next clog change will set the
 	 * LSN correctly.
 	 */
-	if (!XLogRecPtrIsInvalid(lsn))
+	if (XLogRecPtrIsValid(lsn))
 	{
 		int			lsnindex = GetLSNIndex(slotno, xid);
 
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index 5d3fcd62c94..77676d6d035 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -937,7 +937,7 @@ SlruPhysicalWritePage(SlruCtl ctl, int64 pageno, int slotno, SlruWriteAll fdata)
 				max_lsn = this_lsn;
 		}
 
-		if (!XLogRecPtrIsInvalid(max_lsn))
+		if (XLogRecPtrIsValid(max_lsn))
 		{
 			/*
 			 * As noted above, elog(ERROR) is not acceptable here, so if
diff --git a/src/backend/access/transam/timeline.c b/src/backend/access/transam/timeline.c
index 186eb91f609..ec3e323ec0c 100644
--- a/src/backend/access/transam/timeline.c
+++ b/src/backend/access/transam/timeline.c
@@ -549,8 +549,8 @@ tliOfPointInHistory(XLogRecPtr ptr, List *history)
 	{
 		TimeLineHistoryEntry *tle = (TimeLineHistoryEntry *) lfirst(cell);
 
-		if ((XLogRecPtrIsInvalid(tle->begin) || tle->begin <= ptr) &&
-			(XLogRecPtrIsInvalid(tle->end) || ptr < tle->end))
+		if ((!XLogRecPtrIsValid(tle->begin) || tle->begin <= ptr) &&
+			(!XLogRecPtrIsValid(tle->end) || ptr < tle->end))
 		{
 			/* found it */
 			return tle->tli;
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 33369fbe23a..8a92b292e56 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -2547,7 +2547,7 @@ PrepareRedoAdd(FullTransactionId fxid, char *buf,
 	 * the record is added to TwoPhaseState and it should have no
 	 * corresponding file in pg_twophase.
 	 */
-	if (!XLogRecPtrIsInvalid(start_lsn))
+	if (XLogRecPtrIsValid(start_lsn))
 	{
 		char		path[MAXPGPATH];
 
@@ -2587,7 +2587,7 @@ PrepareRedoAdd(FullTransactionId fxid, char *buf,
 	gxact->owner = hdr->owner;
 	gxact->locking_backend = INVALID_PROC_NUMBER;
 	gxact->valid = false;
-	gxact->ondisk = XLogRecPtrIsInvalid(start_lsn);
+	gxact->ondisk = !XLogRecPtrIsValid(start_lsn);
 	gxact->inredo = true;		/* yes, added in redo */
 	strcpy(gxact->gid, gid);
 
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 7c959051e11..0564482cda8 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -1762,7 +1762,7 @@ WALReadFromBuffers(char *dstbuf, XLogRecPtr startptr, Size count,
 	if (RecoveryInProgress() || tli != GetWALInsertionTimeLine())
 		return 0;
 
-	Assert(!XLogRecPtrIsInvalid(startptr));
+	Assert(XLogRecPtrIsValid(startptr));
 
 	/*
 	 * Caller should ensure that the requested data has been inserted into WAL
@@ -2717,7 +2717,7 @@ UpdateMinRecoveryPoint(XLogRecPtr lsn, bool force)
 	 * available is replayed in this case.  This also saves from extra locks
 	 * taken on the control file from the startup process.
 	 */
-	if (XLogRecPtrIsInvalid(LocalMinRecoveryPoint) && InRecovery)
+	if (!XLogRecPtrIsValid(LocalMinRecoveryPoint) && InRecovery)
 	{
 		updateMinRecoveryPoint = false;
 		return;
@@ -2729,7 +2729,7 @@ UpdateMinRecoveryPoint(XLogRecPtr lsn, bool force)
 	LocalMinRecoveryPoint = ControlFile->minRecoveryPoint;
 	LocalMinRecoveryPointTLI = ControlFile->minRecoveryPointTLI;
 
-	if (XLogRecPtrIsInvalid(LocalMinRecoveryPoint))
+	if (!XLogRecPtrIsValid(LocalMinRecoveryPoint))
 		updateMinRecoveryPoint = false;
 	else if (force || LocalMinRecoveryPoint < lsn)
 	{
@@ -3149,7 +3149,7 @@ XLogNeedsFlush(XLogRecPtr record)
 		 * which cannot update its local copy of minRecoveryPoint as long as
 		 * it has not replayed all WAL available when doing crash recovery.
 		 */
-		if (XLogRecPtrIsInvalid(LocalMinRecoveryPoint) && InRecovery)
+		if (!XLogRecPtrIsValid(LocalMinRecoveryPoint) && InRecovery)
 		{
 			updateMinRecoveryPoint = false;
 			return false;
@@ -3170,7 +3170,7 @@ XLogNeedsFlush(XLogRecPtr record)
 		 * process doing crash recovery, which should not update the control
 		 * file value if crash recovery is still running.
 		 */
-		if (XLogRecPtrIsInvalid(LocalMinRecoveryPoint))
+		if (!XLogRecPtrIsValid(LocalMinRecoveryPoint))
 			updateMinRecoveryPoint = false;
 
 		/* check again */
@@ -5935,7 +5935,7 @@ StartupXLOG(void)
 	 */
 	if (InRecovery &&
 		(EndOfLog < LocalMinRecoveryPoint ||
-		 !XLogRecPtrIsInvalid(ControlFile->backupStartPoint)))
+		 XLogRecPtrIsValid(ControlFile->backupStartPoint)))
 	{
 		/*
 		 * Ran off end of WAL before reaching end-of-backup WAL record, or
@@ -5945,7 +5945,7 @@ StartupXLOG(void)
 		 */
 		if (ArchiveRecoveryRequested || ControlFile->backupEndRequired)
 		{
-			if (!XLogRecPtrIsInvalid(ControlFile->backupStartPoint) || ControlFile->backupEndRequired)
+			if (XLogRecPtrIsValid(ControlFile->backupStartPoint) || ControlFile->backupEndRequired)
 				ereport(FATAL,
 						(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 						 errmsg("WAL ends before end of online backup"),
@@ -6047,7 +6047,7 @@ StartupXLOG(void)
 	 * (It's critical to first write an OVERWRITE_CONTRECORD message, which
 	 * we'll do as soon as we're open for writing new WAL.)
 	 */
-	if (!XLogRecPtrIsInvalid(missingContrecPtr))
+	if (XLogRecPtrIsValid(missingContrecPtr))
 	{
 		/*
 		 * We should only have a missingContrecPtr if we're not switching to a
@@ -6057,7 +6057,7 @@ StartupXLOG(void)
 		 * disregard.
 		 */
 		Assert(newTLI == endOfRecoveryInfo->lastRecTLI);
-		Assert(!XLogRecPtrIsInvalid(abortedRecPtr));
+		Assert(XLogRecPtrIsValid(abortedRecPtr));
 		EndOfLog = missingContrecPtr;
 	}
 
@@ -6161,9 +6161,9 @@ StartupXLOG(void)
 	LocalSetXLogInsertAllowed();
 
 	/* If necessary, write overwrite-contrecord before doing anything else */
-	if (!XLogRecPtrIsInvalid(abortedRecPtr))
+	if (XLogRecPtrIsValid(abortedRecPtr))
 	{
-		Assert(!XLogRecPtrIsInvalid(missingContrecPtr));
+		Assert(XLogRecPtrIsValid(missingContrecPtr));
 		CreateOverwriteContrecordRecord(abortedRecPtr, missingContrecPtr, newTLI);
 	}
 
@@ -7693,7 +7693,7 @@ CreateRestartPoint(int flags)
 	 * restartpoint. It's assumed that flushing the buffers will do that as a
 	 * side-effect.
 	 */
-	if (XLogRecPtrIsInvalid(lastCheckPointRecPtr) ||
+	if (!XLogRecPtrIsValid(lastCheckPointRecPtr) ||
 		lastCheckPoint.redo <= ControlFile->checkPointCopy.redo)
 	{
 		ereport(DEBUG2,
@@ -7936,7 +7936,7 @@ GetWALAvailability(XLogRecPtr targetLSN)
 	/*
 	 * slot does not reserve WAL. Either deactivated, or has never been active
 	 */
-	if (XLogRecPtrIsInvalid(targetLSN))
+	if (!XLogRecPtrIsValid(targetLSN))
 		return WALAVAIL_INVALID_LSN;
 
 	/*
@@ -8352,8 +8352,8 @@ xlog_redo(XLogReaderState *record)
 		 * never arrive.
 		 */
 		if (ArchiveRecoveryRequested &&
-			!XLogRecPtrIsInvalid(ControlFile->backupStartPoint) &&
-			XLogRecPtrIsInvalid(ControlFile->backupEndPoint))
+			XLogRecPtrIsValid(ControlFile->backupStartPoint) &&
+			!XLogRecPtrIsValid(ControlFile->backupEndPoint))
 			ereport(PANIC,
 					(errmsg("online backup was canceled, recovery cannot continue")));
 
diff --git a/src/backend/access/transam/xlogbackup.c b/src/backend/access/transam/xlogbackup.c
index 8a8a2a7b326..7e48aa43901 100644
--- a/src/backend/access/transam/xlogbackup.c
+++ b/src/backend/access/transam/xlogbackup.c
@@ -79,8 +79,8 @@ build_backup_content(BackupState *state, bool ishistoryfile)
 	}
 
 	/* either both istartpoint and istarttli should be set, or neither */
-	Assert(XLogRecPtrIsInvalid(state->istartpoint) == (state->istarttli == 0));
-	if (!XLogRecPtrIsInvalid(state->istartpoint))
+	Assert(!XLogRecPtrIsValid(state->istartpoint) == (state->istarttli == 0));
+	if (XLogRecPtrIsValid(state->istartpoint))
 	{
 		appendStringInfo(&result, "INCREMENTAL FROM LSN: %X/%08X\n",
 						 LSN_FORMAT_ARGS(state->istartpoint));
diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index dcc8d4f9c1b..aad16127e60 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -231,7 +231,7 @@ WALOpenSegmentInit(WALOpenSegment *seg, WALSegmentContext *segcxt,
 void
 XLogBeginRead(XLogReaderState *state, XLogRecPtr RecPtr)
 {
-	Assert(!XLogRecPtrIsInvalid(RecPtr));
+	Assert(XLogRecPtrIsValid(RecPtr));
 
 	ResetDecoder(state);
 
@@ -343,7 +343,7 @@ XLogNextRecord(XLogReaderState *state, char **errormsg)
 		 * XLogBeginRead() or XLogNextRecord(), and is the location of the
 		 * error.
 		 */
-		Assert(!XLogRecPtrIsInvalid(state->EndRecPtr));
+		Assert(XLogRecPtrIsValid(state->EndRecPtr));
 
 		return NULL;
 	}
@@ -1398,7 +1398,7 @@ XLogFindNextRecord(XLogReaderState *state, XLogRecPtr RecPtr)
 	XLogPageHeader header;
 	char	   *errormsg;
 
-	Assert(!XLogRecPtrIsInvalid(RecPtr));
+	Assert(XLogRecPtrIsValid(RecPtr));
 
 	/* Make sure ReadPageInternal() can't return XLREAD_WOULDBLOCK. */
 	state->nonblocking = false;
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index 550de6e4a59..bb7b79613c2 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -773,7 +773,7 @@ InitWalRecovery(ControlFileData *ControlFile, bool *wasShutdown_ptr,
 		 * emit a log message when we continue initializing from a base
 		 * backup.
 		 */
-		if (!XLogRecPtrIsInvalid(ControlFile->backupStartPoint))
+		if (XLogRecPtrIsValid(ControlFile->backupStartPoint))
 			ereport(LOG,
 					errmsg("restarting backup recovery with redo LSN %X/%08X",
 						   LSN_FORMAT_ARGS(ControlFile->backupStartPoint)));
@@ -868,7 +868,7 @@ InitWalRecovery(ControlFileData *ControlFile, bool *wasShutdown_ptr,
 	 * The min recovery point should be part of the requested timeline's
 	 * history, too.
 	 */
-	if (!XLogRecPtrIsInvalid(ControlFile->minRecoveryPoint) &&
+	if (XLogRecPtrIsValid(ControlFile->minRecoveryPoint) &&
 		tliOfPointInHistory(ControlFile->minRecoveryPoint - 1, expectedTLEs) !=
 		ControlFile->minRecoveryPointTLI)
 		ereport(FATAL,
@@ -2204,7 +2204,7 @@ CheckRecoveryConsistency(void)
 	 * During crash recovery, we don't reach a consistent state until we've
 	 * replayed all the WAL.
 	 */
-	if (XLogRecPtrIsInvalid(minRecoveryPoint))
+	if (!XLogRecPtrIsValid(minRecoveryPoint))
 		return;
 
 	Assert(InArchiveRecovery);
@@ -2219,7 +2219,7 @@ CheckRecoveryConsistency(void)
 	/*
 	 * Have we reached the point where our base backup was completed?
 	 */
-	if (!XLogRecPtrIsInvalid(backupEndPoint) &&
+	if (XLogRecPtrIsValid(backupEndPoint) &&
 		backupEndPoint <= lastReplayedEndRecPtr)
 	{
 		XLogRecPtr	saveBackupStartPoint = backupStartPoint;
@@ -2425,7 +2425,7 @@ checkTimeLineSwitch(XLogRecPtr lsn, TimeLineID newTLI, TimeLineID prevTLI,
 	 * branched before the timeline the min recovery point is on, and you
 	 * attempt to do PITR to the new timeline.
 	 */
-	if (!XLogRecPtrIsInvalid(minRecoveryPoint) &&
+	if (XLogRecPtrIsValid(minRecoveryPoint) &&
 		lsn < minRecoveryPoint &&
 		newTLI > minRecoveryPointTLI)
 		ereport(PANIC,
@@ -3190,7 +3190,7 @@ ReadRecord(XLogPrefetcher *xlogprefetcher, int emode,
 			 * overwrite contrecord in the wrong place, breaking everything.
 			 */
 			if (!ArchiveRecoveryRequested &&
-				!XLogRecPtrIsInvalid(xlogreader->abortedRecPtr))
+				XLogRecPtrIsValid(xlogreader->abortedRecPtr))
 			{
 				abortedRecPtr = xlogreader->abortedRecPtr;
 				missingContrecPtr = xlogreader->missingContrecPtr;
diff --git a/src/backend/access/transam/xlogwait.c b/src/backend/access/transam/xlogwait.c
index e04567cfd67..6b4c1623e57 100644
--- a/src/backend/access/transam/xlogwait.c
+++ b/src/backend/access/transam/xlogwait.c
@@ -230,7 +230,7 @@ wakeupWaiters(WaitLSNType lsnType, XLogRecPtr currentLSN)
 			/* Get procInfo using appropriate heap node */
 			procInfo = pairingheap_container(WaitLSNProcInfo, heapNode[i], node);
 
-			if (!XLogRecPtrIsInvalid(currentLSN) && procInfo->waitLSN > currentLSN)
+			if (XLogRecPtrIsValid(currentLSN) && procInfo->waitLSN > currentLSN)
 				break;
 
 			Assert(numWakeUpProcs < WAKEUP_PROC_STATIC_ARRAY_SIZE);
diff --git a/src/backend/backup/backup_manifest.c b/src/backend/backup/backup_manifest.c
index d05252f383c..dd76c9b0b63 100644
--- a/src/backend/backup/backup_manifest.c
+++ b/src/backend/backup/backup_manifest.c
@@ -242,7 +242,7 @@ AddWALInfoToBackupManifest(backup_manifest_info *manifest, XLogRecPtr startptr,
 		 * entry->end is InvalidXLogRecPtr, it means that the timeline has not
 		 * yet ended.)
 		 */
-		if (!XLogRecPtrIsInvalid(entry->end) && entry->end < startptr)
+		if (XLogRecPtrIsValid(entry->end) && entry->end < startptr)
 			continue;
 
 		/*
@@ -274,7 +274,7 @@ AddWALInfoToBackupManifest(backup_manifest_info *manifest, XLogRecPtr startptr,
 			 * better have arrived at the expected starting TLI. If not,
 			 * something's gone horribly wrong.
 			 */
-			if (XLogRecPtrIsInvalid(entry->begin))
+			if (!XLogRecPtrIsValid(entry->begin))
 				ereport(ERROR,
 						errmsg("expected start timeline %u but found timeline %u",
 							   starttli, entry->tli));
diff --git a/src/backend/backup/basebackup_incremental.c b/src/backend/backup/basebackup_incremental.c
index a0d48ff0fef..852ab577045 100644
--- a/src/backend/backup/basebackup_incremental.c
+++ b/src/backend/backup/basebackup_incremental.c
@@ -519,7 +519,7 @@ PrepareForIncrementalBackup(IncrementalBackupInfo *ib,
 		if (!WalSummariesAreComplete(tli_wslist, tli_start_lsn, tli_end_lsn,
 									 &tli_missing_lsn))
 		{
-			if (XLogRecPtrIsInvalid(tli_missing_lsn))
+			if (!XLogRecPtrIsValid(tli_missing_lsn))
 				ereport(ERROR,
 						(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 						 errmsg("WAL summaries are required on timeline %u from %X/%08X to %X/%08X, but no summaries for that timeline and LSN range exist",
diff --git a/src/backend/backup/walsummary.c b/src/backend/backup/walsummary.c
index c7a2c65cc6a..2689eae3328 100644
--- a/src/backend/backup/walsummary.c
+++ b/src/backend/backup/walsummary.c
@@ -67,9 +67,9 @@ GetWalSummaries(TimeLineID tli, XLogRecPtr start_lsn, XLogRecPtr end_lsn)
 		/* Skip if it doesn't match the filter criteria. */
 		if (tli != 0 && tli != file_tli)
 			continue;
-		if (!XLogRecPtrIsInvalid(start_lsn) && start_lsn >= file_end_lsn)
+		if (XLogRecPtrIsValid(start_lsn) && start_lsn >= file_end_lsn)
 			continue;
-		if (!XLogRecPtrIsInvalid(end_lsn) && end_lsn <= file_start_lsn)
+		if (XLogRecPtrIsValid(end_lsn) && end_lsn <= file_start_lsn)
 			continue;
 
 		/* Add it to the list. */
@@ -111,9 +111,9 @@ FilterWalSummaries(List *wslist, TimeLineID tli,
 		/* Skip if it doesn't match the filter criteria. */
 		if (tli != 0 && tli != ws->tli)
 			continue;
-		if (!XLogRecPtrIsInvalid(start_lsn) && start_lsn > ws->end_lsn)
+		if (XLogRecPtrIsValid(start_lsn) && start_lsn > ws->end_lsn)
 			continue;
-		if (!XLogRecPtrIsInvalid(end_lsn) && end_lsn < ws->start_lsn)
+		if (XLogRecPtrIsValid(end_lsn) && end_lsn < ws->start_lsn)
 			continue;
 
 		/* Add it to the result list. */
diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c
index 3d29818badd..2b0c0ca8d05 100644
--- a/src/backend/commands/subscriptioncmds.c
+++ b/src/backend/commands/subscriptioncmds.c
@@ -393,7 +393,7 @@ parse_subscription_options(ParseState *pstate, List *stmt_options,
 				lsn = DatumGetLSN(DirectFunctionCall1(pg_lsn_in,
 													  CStringGetDatum(lsn_str)));
 
-				if (XLogRecPtrIsInvalid(lsn))
+				if (!XLogRecPtrIsValid(lsn))
 					ereport(ERROR,
 							(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 							 errmsg("invalid WAL location (LSN): %s", lsn_str)));
@@ -1895,7 +1895,7 @@ AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt,
 				 * If the user sets subskiplsn, we do a sanity check to make
 				 * sure that the specified LSN is a probable value.
 				 */
-				if (!XLogRecPtrIsInvalid(opts.lsn))
+				if (XLogRecPtrIsValid(opts.lsn))
 				{
 					RepOriginId originid;
 					char		originname[NAMEDATALEN];
@@ -1907,7 +1907,7 @@ AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt,
 					remote_lsn = replorigin_get_progress(originid, false);
 
 					/* Check the given LSN is at least a future LSN */
-					if (!XLogRecPtrIsInvalid(remote_lsn) && opts.lsn < remote_lsn)
+					if (XLogRecPtrIsValid(remote_lsn) && opts.lsn < remote_lsn)
 						ereport(ERROR,
 								(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 								 errmsg("skip WAL location (LSN %X/%08X) must be greater than origin LSN %X/%08X",
diff --git a/src/backend/postmaster/walsummarizer.c b/src/backend/postmaster/walsummarizer.c
index e1f142f20c7..c4a888a081c 100644
--- a/src/backend/postmaster/walsummarizer.c
+++ b/src/backend/postmaster/walsummarizer.c
@@ -342,7 +342,7 @@ WalSummarizerMain(const void *startup_data, size_t startup_data_len)
 	 * If we discover that WAL summarization is not enabled, just exit.
 	 */
 	current_lsn = GetOldestUnsummarizedLSN(&current_tli, &exact);
-	if (XLogRecPtrIsInvalid(current_lsn))
+	if (!XLogRecPtrIsValid(current_lsn))
 		proc_exit(0);
 
 	/*
@@ -379,7 +379,7 @@ WalSummarizerMain(const void *startup_data, size_t startup_data_len)
 		 * only have to do this once per timeline switch, we probably wouldn't
 		 * save any significant amount of work in practice.
 		 */
-		if (current_tli != latest_tli && XLogRecPtrIsInvalid(switch_lsn))
+		if (current_tli != latest_tli && !XLogRecPtrIsValid(switch_lsn))
 		{
 			List	   *tles = readTimeLineHistory(latest_tli);
 
@@ -394,7 +394,7 @@ WalSummarizerMain(const void *startup_data, size_t startup_data_len)
 		 * on this timeline. Switch to the next timeline and go around again,
 		 * backing up to the exact switch point if we passed it.
 		 */
-		if (!XLogRecPtrIsInvalid(switch_lsn) && current_lsn >= switch_lsn)
+		if (XLogRecPtrIsValid(switch_lsn) && current_lsn >= switch_lsn)
 		{
 			/* Restart summarization from switch point. */
 			current_tli = switch_tli;
@@ -419,7 +419,7 @@ WalSummarizerMain(const void *startup_data, size_t startup_data_len)
 		end_of_summary_lsn = SummarizeWAL(current_tli,
 										  current_lsn, exact,
 										  switch_lsn, latest_lsn);
-		Assert(!XLogRecPtrIsInvalid(end_of_summary_lsn));
+		Assert(XLogRecPtrIsValid(end_of_summary_lsn));
 		Assert(end_of_summary_lsn >= current_lsn);
 
 		/*
@@ -923,7 +923,7 @@ SummarizeWAL(TimeLineID tli, XLogRecPtr start_lsn, bool exact,
 	private_data = (SummarizerReadLocalXLogPrivate *)
 		palloc0(sizeof(SummarizerReadLocalXLogPrivate));
 	private_data->tli = tli;
-	private_data->historic = !XLogRecPtrIsInvalid(switch_lsn);
+	private_data->historic = XLogRecPtrIsValid(switch_lsn);
 	private_data->read_upto = maximum_lsn;
 
 	/* Create xlogreader. */
@@ -971,7 +971,7 @@ SummarizeWAL(TimeLineID tli, XLogRecPtr start_lsn, bool exact,
 	else
 	{
 		summary_start_lsn = XLogFindNextRecord(xlogreader, start_lsn);
-		if (XLogRecPtrIsInvalid(summary_start_lsn))
+		if (!XLogRecPtrIsValid(summary_start_lsn))
 		{
 			/*
 			 * If we hit end-of-WAL while trying to find the next valid
@@ -1058,7 +1058,7 @@ SummarizeWAL(TimeLineID tli, XLogRecPtr start_lsn, bool exact,
 		/* We shouldn't go backward. */
 		Assert(summary_start_lsn <= xlogreader->EndRecPtr);
 
-		if (!XLogRecPtrIsInvalid(switch_lsn) &&
+		if (XLogRecPtrIsValid(switch_lsn) &&
 			xlogreader->ReadRecPtr >= switch_lsn)
 		{
 			/*
@@ -1180,7 +1180,7 @@ SummarizeWAL(TimeLineID tli, XLogRecPtr start_lsn, bool exact,
 		 * If we have a switch LSN and have reached it, stop before reading
 		 * the next record.
 		 */
-		if (!XLogRecPtrIsInvalid(switch_lsn) &&
+		if (XLogRecPtrIsValid(switch_lsn) &&
 			xlogreader->EndRecPtr >= switch_lsn)
 			break;
 	}
@@ -1723,7 +1723,7 @@ MaybeRemoveOldWalSummaries(void)
 			 * If the WAL doesn't exist any more, we can remove it if the file
 			 * modification time is old enough.
 			 */
-			if (XLogRecPtrIsInvalid(oldest_lsn) || ws->end_lsn <= oldest_lsn)
+			if (!XLogRecPtrIsValid(oldest_lsn) || ws->end_lsn <= oldest_lsn)
 				RemoveWalSummaryIfOlderThan(ws, cutoff_time);
 
 			/*
diff --git a/src/backend/replication/logical/applyparallelworker.c b/src/backend/replication/logical/applyparallelworker.c
index 14325581afc..baa68c1ab6c 100644
--- a/src/backend/replication/logical/applyparallelworker.c
+++ b/src/backend/replication/logical/applyparallelworker.c
@@ -299,7 +299,7 @@ pa_can_start(void)
 	 * STREAM START message, and it doesn't seem worth sending the extra eight
 	 * bytes with the STREAM START to enable parallelism for this case.
 	 */
-	if (!XLogRecPtrIsInvalid(MySubscription->skiplsn))
+	if (XLogRecPtrIsValid(MySubscription->skiplsn))
 		return false;
 
 	/*
@@ -1640,7 +1640,7 @@ pa_xact_finish(ParallelApplyWorkerInfo *winfo, XLogRecPtr remote_lsn)
 	 */
 	pa_wait_for_xact_finish(winfo);
 
-	if (!XLogRecPtrIsInvalid(remote_lsn))
+	if (XLogRecPtrIsValid(remote_lsn))
 		store_flush_position(remote_lsn, winfo->shared->last_commit_end);
 
 	pa_free_worker(winfo);
diff --git a/src/backend/replication/logical/launcher.c b/src/backend/replication/logical/launcher.c
index 6c6d4015ba7..6214028eda9 100644
--- a/src/backend/replication/logical/launcher.c
+++ b/src/backend/replication/logical/launcher.c
@@ -1661,7 +1661,7 @@ pg_stat_get_subscription(PG_FUNCTION_ARGS)
 		else
 			nulls[3] = true;
 
-		if (XLogRecPtrIsInvalid(worker.last_lsn))
+		if (!XLogRecPtrIsValid(worker.last_lsn))
 			nulls[4] = true;
 		else
 			values[4] = LSNGetDatum(worker.last_lsn);
@@ -1673,7 +1673,7 @@ pg_stat_get_subscription(PG_FUNCTION_ARGS)
 			nulls[6] = true;
 		else
 			values[6] = TimestampTzGetDatum(worker.last_recv_time);
-		if (XLogRecPtrIsInvalid(worker.reply_lsn))
+		if (!XLogRecPtrIsValid(worker.reply_lsn))
 			nulls[7] = true;
 		else
 			values[7] = LSNGetDatum(worker.reply_lsn);
diff --git a/src/backend/replication/logical/logical.c b/src/backend/replication/logical/logical.c
index 93ed2eb368e..79717b52941 100644
--- a/src/backend/replication/logical/logical.c
+++ b/src/backend/replication/logical/logical.c
@@ -388,7 +388,7 @@ CreateInitDecodingContext(const char *plugin,
 	slot->data.plugin = plugin_name;
 	SpinLockRelease(&slot->mutex);
 
-	if (XLogRecPtrIsInvalid(restart_lsn))
+	if (!XLogRecPtrIsValid(restart_lsn))
 		ReplicationSlotReserveWal();
 	else
 	{
diff --git a/src/backend/replication/logical/logicalfuncs.c b/src/backend/replication/logical/logicalfuncs.c
index 25f890ddeed..d78e486bca6 100644
--- a/src/backend/replication/logical/logicalfuncs.c
+++ b/src/backend/replication/logical/logicalfuncs.c
@@ -229,7 +229,7 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin
 		 * Wait for specified streaming replication standby servers (if any)
 		 * to confirm receipt of WAL up to wait_for_wal_lsn.
 		 */
-		if (XLogRecPtrIsInvalid(upto_lsn))
+		if (!XLogRecPtrIsValid(upto_lsn))
 			wait_for_wal_lsn = end_of_wal;
 		else
 			wait_for_wal_lsn = Min(upto_lsn, end_of_wal);
diff --git a/src/backend/replication/logical/slotsync.c b/src/backend/replication/logical/slotsync.c
index b122d99b009..8b4afd87dc9 100644
--- a/src/backend/replication/logical/slotsync.c
+++ b/src/backend/replication/logical/slotsync.c
@@ -493,7 +493,7 @@ reserve_wal_for_local_slot(XLogRecPtr restart_lsn)
 	ReplicationSlot *slot = MyReplicationSlot;
 
 	Assert(slot != NULL);
-	Assert(XLogRecPtrIsInvalid(slot->data.restart_lsn));
+	Assert(!XLogRecPtrIsValid(slot->data.restart_lsn));
 
 	while (true)
 	{
@@ -899,8 +899,8 @@ synchronize_slots(WalReceiverConn *wrconn)
 		 * pg_replication_slots view, then we can avoid fetching RS_EPHEMERAL
 		 * slots in the first place.
 		 */
-		if ((XLogRecPtrIsInvalid(remote_slot->restart_lsn) ||
-			 XLogRecPtrIsInvalid(remote_slot->confirmed_lsn) ||
+		if ((!XLogRecPtrIsValid(remote_slot->restart_lsn) ||
+			 !XLogRecPtrIsValid(remote_slot->confirmed_lsn) ||
 			 !TransactionIdIsValid(remote_slot->catalog_xmin)) &&
 			remote_slot->invalidated == RS_INVAL_NONE)
 			pfree(remote_slot);
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index e1c757c911e..28f61f96a1a 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -514,7 +514,7 @@ bool		InitializingApplyWorker = false;
  * by the user.
  */
 static XLogRecPtr skip_xact_finish_lsn = InvalidXLogRecPtr;
-#define is_skipping_changes() (unlikely(!XLogRecPtrIsInvalid(skip_xact_finish_lsn)))
+#define is_skipping_changes() (unlikely(XLogRecPtrIsValid(skip_xact_finish_lsn)))
 
 /* BufFile handle of the current streaming file */
 static BufFile *stream_fd = NULL;
@@ -4126,7 +4126,7 @@ LogicalRepApplyLoop(XLogRecPtr last_received)
 						 * due to a bug, we don't want to proceed as it can
 						 * incorrectly advance oldest_nonremovable_xid.
 						 */
-						if (XLogRecPtrIsInvalid(rdt_data.remote_lsn))
+						if (!XLogRecPtrIsValid(rdt_data.remote_lsn))
 							elog(ERROR, "cannot get the latest WAL position from the publisher");
 
 						maybe_advance_nonremovable_xid(&rdt_data, true);
@@ -4613,7 +4613,7 @@ wait_for_publisher_status(RetainDeadTuplesData *rdt_data,
 static void
 wait_for_local_flush(RetainDeadTuplesData *rdt_data)
 {
-	Assert(!XLogRecPtrIsInvalid(rdt_data->remote_lsn) &&
+	Assert(XLogRecPtrIsValid(rdt_data->remote_lsn) &&
 		   TransactionIdIsValid(rdt_data->candidate_xid));
 
 	/*
@@ -6031,7 +6031,7 @@ maybe_start_skipping_changes(XLogRecPtr finish_lsn)
 	 * function is called for every remote transaction and we assume that
 	 * skipping the transaction is not used often.
 	 */
-	if (likely(XLogRecPtrIsInvalid(MySubscription->skiplsn) ||
+	if (likely(!XLogRecPtrIsValid(MySubscription->skiplsn) ||
 			   MySubscription->skiplsn != finish_lsn))
 		return;
 
@@ -6077,7 +6077,7 @@ clear_subscription_skip_lsn(XLogRecPtr finish_lsn)
 	XLogRecPtr	myskiplsn = MySubscription->skiplsn;
 	bool		started_tx = false;
 
-	if (likely(XLogRecPtrIsInvalid(myskiplsn)) || am_parallel_apply_worker())
+	if (likely(!XLogRecPtrIsValid(myskiplsn)) || am_parallel_apply_worker())
 		return;
 
 	if (!IsTransactionState())
@@ -6173,7 +6173,7 @@ apply_error_callback(void *arg)
 			errcontext("processing remote data for replication origin \"%s\" during message type \"%s\"",
 					   errarg->origin_name,
 					   logicalrep_message_type(errarg->command));
-		else if (XLogRecPtrIsInvalid(errarg->finish_lsn))
+		else if (!XLogRecPtrIsValid(errarg->finish_lsn))
 			errcontext("processing remote data for replication origin \"%s\" during message type \"%s\" in transaction %u",
 					   errarg->origin_name,
 					   logicalrep_message_type(errarg->command),
@@ -6189,7 +6189,7 @@ apply_error_callback(void *arg)
 	{
 		if (errarg->remote_attnum < 0)
 		{
-			if (XLogRecPtrIsInvalid(errarg->finish_lsn))
+			if (!XLogRecPtrIsValid(errarg->finish_lsn))
 				errcontext("processing remote data for replication origin \"%s\" during message type \"%s\" for replication target relation \"%s.%s\" in transaction %u",
 						   errarg->origin_name,
 						   logicalrep_message_type(errarg->command),
@@ -6207,7 +6207,7 @@ apply_error_callback(void *arg)
 		}
 		else
 		{
-			if (XLogRecPtrIsInvalid(errarg->finish_lsn))
+			if (!XLogRecPtrIsValid(errarg->finish_lsn))
 				errcontext("processing remote data for replication origin \"%s\" during message type \"%s\" for replication target relation \"%s.%s\" column \"%s\" in transaction %u",
 						   errarg->origin_name,
 						   logicalrep_message_type(errarg->command),
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index 6363030808f..0cb93dc90f2 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -1730,7 +1730,7 @@ static inline bool
 CanInvalidateIdleSlot(ReplicationSlot *s)
 {
 	return (idle_replication_slot_timeout_secs != 0 &&
-			!XLogRecPtrIsInvalid(s->data.restart_lsn) &&
+			XLogRecPtrIsValid(s->data.restart_lsn) &&
 			s->inactive_since > 0 &&
 			!(RecoveryInProgress() && s->data.synced));
 }
@@ -2922,7 +2922,7 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
 	 * Don't need to wait for the standbys to catch up if they are already
 	 * beyond the specified WAL location.
 	 */
-	if (!XLogRecPtrIsInvalid(ss_oldest_flush_lsn) &&
+	if (XLogRecPtrIsValid(ss_oldest_flush_lsn) &&
 		ss_oldest_flush_lsn >= wait_for_lsn)
 		return true;
 
@@ -2993,7 +2993,7 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
 			break;
 		}
 
-		if (XLogRecPtrIsInvalid(restart_lsn) || restart_lsn < wait_for_lsn)
+		if (!XLogRecPtrIsValid(restart_lsn) || restart_lsn < wait_for_lsn)
 		{
 			/* Log a message if no active_pid for this physical slot */
 			if (inactive)
@@ -3012,7 +3012,7 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
 
 		Assert(restart_lsn >= wait_for_lsn);
 
-		if (XLogRecPtrIsInvalid(min_restart_lsn) ||
+		if (!XLogRecPtrIsValid(min_restart_lsn) ||
 			min_restart_lsn > restart_lsn)
 			min_restart_lsn = restart_lsn;
 
@@ -3031,7 +3031,7 @@ StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
 		return false;
 
 	/* The ss_oldest_flush_lsn must not retreat. */
-	Assert(XLogRecPtrIsInvalid(ss_oldest_flush_lsn) ||
+	Assert(!XLogRecPtrIsValid(ss_oldest_flush_lsn) ||
 		   min_restart_lsn >= ss_oldest_flush_lsn);
 
 	ss_oldest_flush_lsn = min_restart_lsn;
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index b8f21153e7b..5aecd5c6a50 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -46,7 +46,7 @@ create_physical_replication_slot(char *name, bool immediately_reserve,
 	if (immediately_reserve)
 	{
 		/* Reserve WAL as the user asked for it */
-		if (XLogRecPtrIsInvalid(restart_lsn))
+		if (!XLogRecPtrIsValid(restart_lsn))
 			ReplicationSlotReserveWal();
 		else
 			MyReplicationSlot->data.restart_lsn = restart_lsn;
@@ -357,7 +357,7 @@ pg_get_replication_slots(PG_FUNCTION_ARGS)
 				 *
 				 * If we do change it, save the state for safe_wal_size below.
 				 */
-				if (!XLogRecPtrIsInvalid(slot_contents.data.restart_lsn))
+				if (XLogRecPtrIsValid(slot_contents.data.restart_lsn))
 				{
 					int			pid;
 
@@ -407,7 +407,7 @@ pg_get_replication_slots(PG_FUNCTION_ARGS)
 		values[i++] = BoolGetDatum(slot_contents.data.two_phase);
 
 		if (slot_contents.data.two_phase &&
-			!XLogRecPtrIsInvalid(slot_contents.data.two_phase_at))
+			XLogRecPtrIsValid(slot_contents.data.two_phase_at))
 			values[i++] = LSNGetDatum(slot_contents.data.two_phase_at);
 		else
 			nulls[i++] = true;
@@ -523,7 +523,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 
 	CheckSlotPermissions();
 
-	if (XLogRecPtrIsInvalid(moveto))
+	if (!XLogRecPtrIsValid(moveto))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("invalid target WAL LSN")));
@@ -545,7 +545,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	ReplicationSlotAcquire(NameStr(*slotname), true, true);
 
 	/* A slot whose restart_lsn has never been reserved cannot be advanced */
-	if (XLogRecPtrIsInvalid(MyReplicationSlot->data.restart_lsn))
+	if (!XLogRecPtrIsValid(MyReplicationSlot->data.restart_lsn))
 		ereport(ERROR,
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 				 errmsg("replication slot \"%s\" cannot be advanced",
@@ -679,7 +679,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 						NameStr(*src_name))));
 
 	/* Copying non-reserved slot doesn't make sense */
-	if (XLogRecPtrIsInvalid(src_restart_lsn))
+	if (!XLogRecPtrIsValid(src_restart_lsn))
 		ereport(ERROR,
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 				 errmsg("cannot copy a replication slot that doesn't reserve WAL")));
@@ -785,7 +785,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 					 errdetail("The source replication slot was modified incompatibly during the copy operation.")));
 
 		/* The source slot must have a consistent snapshot */
-		if (src_islogical && XLogRecPtrIsInvalid(copy_confirmed_flush))
+		if (src_islogical && !XLogRecPtrIsValid(copy_confirmed_flush))
 			ereport(ERROR,
 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 					 errmsg("cannot copy unfinished logical replication slot \"%s\"",
@@ -840,7 +840,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 	/* All done.  Set up the return values */
 	values[0] = NameGetDatum(dst_name);
 	nulls[0] = false;
-	if (!XLogRecPtrIsInvalid(MyReplicationSlot->data.confirmed_flush))
+	if (XLogRecPtrIsValid(MyReplicationSlot->data.confirmed_flush))
 	{
 		values[1] = LSNGetDatum(MyReplicationSlot->data.confirmed_flush);
 		nulls[1] = false;
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index 32cf3a48b89..a0c79958fd5 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -493,7 +493,7 @@ SyncRepReleaseWaiters(void)
 	if (MyWalSnd->sync_standby_priority == 0 ||
 		(MyWalSnd->state != WALSNDSTATE_STREAMING &&
 		 MyWalSnd->state != WALSNDSTATE_STOPPING) ||
-		XLogRecPtrIsInvalid(MyWalSnd->flush))
+		!XLogRecPtrIsValid(MyWalSnd->flush))
 	{
 		announce_next_takeover = true;
 		return;
@@ -676,11 +676,11 @@ SyncRepGetOldestSyncRecPtr(XLogRecPtr *writePtr,
 		XLogRecPtr	flush = sync_standbys[i].flush;
 		XLogRecPtr	apply = sync_standbys[i].apply;
 
-		if (XLogRecPtrIsInvalid(*writePtr) || *writePtr > write)
+		if (!XLogRecPtrIsValid(*writePtr) || *writePtr > write)
 			*writePtr = write;
-		if (XLogRecPtrIsInvalid(*flushPtr) || *flushPtr > flush)
+		if (!XLogRecPtrIsValid(*flushPtr) || *flushPtr > flush)
 			*flushPtr = flush;
-		if (XLogRecPtrIsInvalid(*applyPtr) || *applyPtr > apply)
+		if (!XLogRecPtrIsValid(*applyPtr) || *applyPtr > apply)
 			*applyPtr = apply;
 	}
 }
@@ -799,7 +799,7 @@ SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
 			continue;
 
 		/* Must have a valid flush position */
-		if (XLogRecPtrIsInvalid(stby->flush))
+		if (!XLogRecPtrIsValid(stby->flush))
 			continue;
 
 		/* OK, it's a candidate */
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index 7361ffc9dcf..2ee8fecee26 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1469,16 +1469,16 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	{
 		values[1] = CStringGetTextDatum(WalRcvGetStateString(state));
 
-		if (XLogRecPtrIsInvalid(receive_start_lsn))
+		if (!XLogRecPtrIsValid(receive_start_lsn))
 			nulls[2] = true;
 		else
 			values[2] = LSNGetDatum(receive_start_lsn);
 		values[3] = Int32GetDatum(receive_start_tli);
-		if (XLogRecPtrIsInvalid(written_lsn))
+		if (!XLogRecPtrIsValid(written_lsn))
 			nulls[4] = true;
 		else
 			values[4] = LSNGetDatum(written_lsn);
-		if (XLogRecPtrIsInvalid(flushed_lsn))
+		if (!XLogRecPtrIsValid(flushed_lsn))
 			nulls[5] = true;
 		else
 			values[5] = LSNGetDatum(flushed_lsn);
@@ -1491,7 +1491,7 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 			nulls[8] = true;
 		else
 			values[8] = TimestampTzGetDatum(last_receipt_time);
-		if (XLogRecPtrIsInvalid(latest_end_lsn))
+		if (!XLogRecPtrIsValid(latest_end_lsn))
 			nulls[9] = true;
 		else
 			values[9] = LSNGetDatum(latest_end_lsn);
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 548eafa7a73..b6dfb230d0d 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -529,7 +529,7 @@ ReadReplicationSlot(ReadReplicationSlotCmd *cmd)
 		i++;
 
 		/* start LSN */
-		if (!XLogRecPtrIsInvalid(slot_contents.data.restart_lsn))
+		if (XLogRecPtrIsValid(slot_contents.data.restart_lsn))
 		{
 			char		xloc[64];
 
@@ -541,7 +541,7 @@ ReadReplicationSlot(ReadReplicationSlotCmd *cmd)
 		i++;
 
 		/* timeline this WAL was produced on */
-		if (!XLogRecPtrIsInvalid(slot_contents.data.restart_lsn))
+		if (XLogRecPtrIsValid(slot_contents.data.restart_lsn))
 		{
 			TimeLineID	slots_position_timeline;
 			TimeLineID	current_timeline;
@@ -906,7 +906,7 @@ StartReplication(StartReplicationCmd *cmd)
 			 * that's older than the switchpoint, if it's still in the same
 			 * WAL segment.
 			 */
-			if (!XLogRecPtrIsInvalid(switchpoint) &&
+			if (XLogRecPtrIsValid(switchpoint) &&
 				switchpoint < cmd->startpoint)
 			{
 				ereport(ERROR,
@@ -1827,7 +1827,7 @@ WalSndWaitForWal(XLogRecPtr loc)
 	 * receipt of WAL up to RecentFlushPtr. This is particularly interesting
 	 * if we're far behind.
 	 */
-	if (!XLogRecPtrIsInvalid(RecentFlushPtr) &&
+	if (XLogRecPtrIsValid(RecentFlushPtr) &&
 		!NeedToWaitForWal(loc, RecentFlushPtr, &wait_event))
 		return RecentFlushPtr;
 
@@ -3597,7 +3597,7 @@ WalSndDone(WalSndSendDataCallback send_data)
 	 * flush location if valid, write otherwise. Tools like pg_receivewal will
 	 * usually (unless in synchronous mode) return an invalid flush location.
 	 */
-	replicatedPtr = XLogRecPtrIsInvalid(MyWalSnd->flush) ?
+	replicatedPtr = !XLogRecPtrIsValid(MyWalSnd->flush) ?
 		MyWalSnd->write : MyWalSnd->flush;
 
 	if (WalSndCaughtUp && sentPtr == replicatedPtr &&
@@ -4073,19 +4073,19 @@ pg_stat_get_wal_senders(PG_FUNCTION_ARGS)
 		{
 			values[1] = CStringGetTextDatum(WalSndGetStateString(state));
 
-			if (XLogRecPtrIsInvalid(sent_ptr))
+			if (!XLogRecPtrIsValid(sent_ptr))
 				nulls[2] = true;
 			values[2] = LSNGetDatum(sent_ptr);
 
-			if (XLogRecPtrIsInvalid(write))
+			if (!XLogRecPtrIsValid(write))
 				nulls[3] = true;
 			values[3] = LSNGetDatum(write);
 
-			if (XLogRecPtrIsInvalid(flush))
+			if (!XLogRecPtrIsValid(flush))
 				nulls[4] = true;
 			values[4] = LSNGetDatum(flush);
 
-			if (XLogRecPtrIsInvalid(apply))
+			if (!XLogRecPtrIsValid(apply))
 				nulls[5] = true;
 			values[5] = LSNGetDatum(apply);
 
@@ -4094,7 +4094,7 @@ pg_stat_get_wal_senders(PG_FUNCTION_ARGS)
 			 * which always returns an invalid flush location, as an
 			 * asynchronous standby.
 			 */
-			priority = XLogRecPtrIsInvalid(flush) ? 0 : priority;
+			priority = !XLogRecPtrIsValid(flush) ? 0 : priority;
 
 			if (writeLag < 0)
 				nulls[6] = true;
@@ -4165,7 +4165,7 @@ WalSndKeepalive(bool requestReply, XLogRecPtr writePtr)
 	/* construct the message... */
 	resetStringInfo(&output_message);
 	pq_sendbyte(&output_message, PqReplMsg_Keepalive);
-	pq_sendint64(&output_message, XLogRecPtrIsInvalid(writePtr) ? sentPtr : writePtr);
+	pq_sendint64(&output_message, !XLogRecPtrIsValid(writePtr) ? sentPtr : writePtr);
 	pq_sendint64(&output_message, GetCurrentTimestamp());
 	pq_sendbyte(&output_message, requestReply ? 1 : 0);
 
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 00719c7aea2..f830f2c6ff3 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -5545,7 +5545,7 @@ MarkBufferDirtyHint(Buffer buffer, bool buffer_std)
 			 * checksum here. That will happen when the page is written
 			 * sometime later in this checkpoint cycle.
 			 */
-			if (!XLogRecPtrIsInvalid(lsn))
+			if (XLogRecPtrIsValid(lsn))
 				PageSetLSN(page, lsn);
 		}
 
diff --git a/src/bin/pg_basebackup/pg_receivewal.c b/src/bin/pg_basebackup/pg_receivewal.c
index 289ca14dcfe..3e6f4a7fc48 100644
--- a/src/bin/pg_basebackup/pg_receivewal.c
+++ b/src/bin/pg_basebackup/pg_receivewal.c
@@ -192,7 +192,7 @@ stop_streaming(XLogRecPtr xlogpos, uint32 timeline, bool segment_finished)
 					LSN_FORMAT_ARGS(xlogpos),
 					timeline);
 
-	if (!XLogRecPtrIsInvalid(endpos) && endpos < xlogpos)
+	if (XLogRecPtrIsValid(endpos) && endpos < xlogpos)
 	{
 		if (verbose)
 			pg_log_info("stopped log streaming at %X/%08X (timeline %u)",
diff --git a/src/bin/pg_basebackup/pg_recvlogical.c b/src/bin/pg_basebackup/pg_recvlogical.c
index 7a4d1a2d2ca..6739784a993 100644
--- a/src/bin/pg_basebackup/pg_recvlogical.c
+++ b/src/bin/pg_basebackup/pg_recvlogical.c
@@ -1080,7 +1080,7 @@ prepareToTerminate(PGconn *conn, XLogRecPtr endpos, StreamStopReason reason,
 							LSN_FORMAT_ARGS(endpos));
 				break;
 			case STREAM_STOP_END_OF_WAL:
-				Assert(!XLogRecPtrIsInvalid(lsn));
+				Assert(XLogRecPtrIsValid(lsn));
 				pg_log_info("end position %X/%08X reached by WAL record at %X/%08X",
 							LSN_FORMAT_ARGS(endpos), LSN_FORMAT_ARGS(lsn));
 				break;
diff --git a/src/bin/pg_rewind/pg_rewind.c b/src/bin/pg_rewind/pg_rewind.c
index 1b953692b17..27c514f934a 100644
--- a/src/bin/pg_rewind/pg_rewind.c
+++ b/src/bin/pg_rewind/pg_rewind.c
@@ -850,9 +850,9 @@ progress_report(bool finished)
 static XLogRecPtr
 MinXLogRecPtr(XLogRecPtr a, XLogRecPtr b)
 {
-	if (XLogRecPtrIsInvalid(a))
+	if (!XLogRecPtrIsValid(a))
 		return b;
-	else if (XLogRecPtrIsInvalid(b))
+	else if (!XLogRecPtrIsValid(b))
 		return a;
 	else
 		return Min(a, b);
diff --git a/src/bin/pg_waldump/pg_waldump.c b/src/bin/pg_waldump/pg_waldump.c
index 13d3ec2f5be..19cf5461eac 100644
--- a/src/bin/pg_waldump/pg_waldump.c
+++ b/src/bin/pg_waldump/pg_waldump.c
@@ -637,7 +637,7 @@ XLogDumpDisplayStats(XLogDumpConfig *config, XLogStats *stats)
 	/*
 	 * Leave if no stats have been computed yet, as tracked by the end LSN.
 	 */
-	if (XLogRecPtrIsInvalid(stats->endptr))
+	if (!XLogRecPtrIsValid(stats->endptr))
 		return;
 
 	/*
@@ -1136,7 +1136,7 @@ main(int argc, char **argv)
 		/* parse position from file */
 		XLogFromFileName(fname, &private.timeline, &segno, WalSegSz);
 
-		if (XLogRecPtrIsInvalid(private.startptr))
+		if (!XLogRecPtrIsValid(private.startptr))
 			XLogSegNoOffsetToRecPtr(segno, 0, WalSegSz, private.startptr);
 		else if (!XLByteInSeg(private.startptr, segno, WalSegSz))
 		{
@@ -1147,7 +1147,7 @@ main(int argc, char **argv)
 		}
 
 		/* no second file specified, set end position */
-		if (!(optind + 1 < argc) && XLogRecPtrIsInvalid(private.endptr))
+		if (!(optind + 1 < argc) && !XLogRecPtrIsValid(private.endptr))
 			XLogSegNoOffsetToRecPtr(segno + 1, 0, WalSegSz, private.endptr);
 
 		/* parse ENDSEG if passed */
@@ -1170,7 +1170,7 @@ main(int argc, char **argv)
 				pg_fatal("ENDSEG %s is before STARTSEG %s",
 						 argv[optind + 1], argv[optind]);
 
-			if (XLogRecPtrIsInvalid(private.endptr))
+			if (!XLogRecPtrIsValid(private.endptr))
 				XLogSegNoOffsetToRecPtr(endsegno + 1, 0, WalSegSz,
 										private.endptr);
 
@@ -1192,7 +1192,7 @@ main(int argc, char **argv)
 		waldir = identify_target_directory(waldir, NULL);
 
 	/* we don't know what to print */
-	if (XLogRecPtrIsInvalid(private.startptr))
+	if (!XLogRecPtrIsValid(private.startptr))
 	{
 		pg_log_error("no start WAL location given");
 		goto bad_argument;
-- 
2.34.1

v6-0003-Introduce-pg_attribute_deprecated-and-deprecate-X.patchtext/x-diff; charset=us-asciiDownload
From ade5179c3e8eb797c2a67e241aee49a0c53df72a Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Mon, 3 Nov 2025 06:33:01 +0000
Subject: [PATCH v6 3/5] Introduce pg_attribute_deprecated() and deprecate
 XLogRecPtrIsInvalid()

This commit creates a new macro pg_attribute_deprecated() to mark a declaration
as deprecated with a custom message. The compiler will emit a warning when the
deprecated entity is used.

Then it makes use of this new macro to emit a deprecated message about
XLogRecPtrIsInvalid() as of version 24 (means until the new macro is available
on all the supported major versions).
---
 src/include/access/xlogdefs.h | 14 +++++++++++---
 src/include/c.h               | 15 +++++++++++++++
 2 files changed, 26 insertions(+), 3 deletions(-)
  45.0% src/include/access/
  54.9% src/include/

diff --git a/src/include/access/xlogdefs.h b/src/include/access/xlogdefs.h
index b16b2a1c8a3..b0be7ca3a67 100644
--- a/src/include/access/xlogdefs.h
+++ b/src/include/access/xlogdefs.h
@@ -32,10 +32,18 @@ typedef uint64 XLogRecPtr;
  * New code should use XLogRecPtrIsValid() instead of XLogRecPtrIsInvalid()
  * for consistency with the affirmative form of other *IsValid() macros and to
  * avoid awkward double negative.
- * This macro is retained for convenience of third-party code but could
- * be deprecated in the future.
+ * This function is retained for convenience of third-party code but is/will be
+ * deprecated as of version 24.
  */
-#define XLogRecPtrIsInvalid(r)	((r) == InvalidXLogRecPtr)
+#if PG_VERSION_NUM >= 240000
+pg_attribute_deprecated("use XLogRecPtrIsValid() instead")
+#endif
+static inline bool
+XLogRecPtrIsInvalid(XLogRecPtr ptr)
+{
+	return ptr == InvalidXLogRecPtr;
+}
+
 /*
  * First LSN to use for "fake" LSNs.
  *
diff --git a/src/include/c.h b/src/include/c.h
index 757dfff4782..6e7b2c47251 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -227,6 +227,21 @@
 #define PG_USED_FOR_ASSERTS_ONLY pg_attribute_unused()
 #endif
 
+/*
+ * Mark a declaration as deprecated with a custom message. The compiler will
+ * emit a warning when the deprecated entity is used.
+ */
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L || \
+defined(__cplusplus) && __cplusplus >= 201402L
+#define pg_attribute_deprecated(msg) [[deprecated(msg)]]
+#elif defined(__GNUC__) || defined(__clang__)
+#define pg_attribute_deprecated(msg) __attribute__((deprecated(msg)))
+#elif defined(_MSC_VER)
+#define pg_attribute_deprecated(msg) __declspec(deprecated(msg))
+#else
+#define pg_attribute_deprecated(msg)
+#endif
+
 /* GCC supports format attributes */
 #if defined(__GNUC__)
 #define pg_attribute_format_arg(a) __attribute__((format_arg(a)))
-- 
2.34.1

v6-0004-Replace-InvalidXLogRecPtr-comparisons-with-XLogRe.patchtext/x-diff; charset=us-asciiDownload
From 042d54af5b12056b6a2fad8f2c270ee0e35fd870 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Wed, 29 Oct 2025 11:45:52 +0000
Subject: [PATCH v6 4/5] Replace InvalidXLogRecPtr comparisons with
 XLogRecPtrIsValid()

This commit ensures the XLogRecPtrIsValid() macro is used instead of direct
InvalidXLogRecPtr equality comparisons.
---
 src/backend/access/heap/rewriteheap.c         |  4 +-
 src/backend/access/heap/vacuumlazy.c          |  2 +-
 src/backend/access/transam/twophase.c         |  2 +-
 src/backend/access/transam/xlog.c             | 18 ++++-----
 src/backend/access/transam/xloginsert.c       |  4 +-
 src/backend/access/transam/xlogreader.c       |  2 +-
 src/backend/access/transam/xlogrecovery.c     |  8 ++--
 src/backend/access/transam/xlogutils.c        |  8 ++--
 src/backend/catalog/pg_subscription.c         |  4 +-
 src/backend/replication/logical/logical.c     | 30 +++++++--------
 .../replication/logical/logicalfuncs.c        |  4 +-
 src/backend/replication/logical/origin.c      | 18 ++++-----
 src/backend/replication/logical/proto.c       | 18 ++++-----
 .../replication/logical/reorderbuffer.c       | 38 +++++++++----------
 src/backend/replication/logical/snapbuild.c   | 14 +++----
 src/backend/replication/slot.c                | 18 ++++-----
 src/backend/replication/slotfuncs.c           |  6 +--
 src/backend/replication/walsender.c           |  6 +--
 src/bin/pg_basebackup/pg_receivewal.c         |  6 +--
 src/bin/pg_basebackup/pg_recvlogical.c        | 10 ++---
 src/bin/pg_waldump/pg_waldump.c               |  4 +-
 src/include/access/xlogdefs.h                 |  2 +-
 22 files changed, 113 insertions(+), 113 deletions(-)
  19.4% src/backend/access/transam/
  54.8% src/backend/replication/logical/
  12.3% src/backend/replication/
   3.6% src/backend/
   7.6% src/bin/pg_basebackup/

diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c
index 8061e92f044..66ab48f0fe0 100644
--- a/src/backend/access/heap/rewriteheap.c
+++ b/src/backend/access/heap/rewriteheap.c
@@ -1169,7 +1169,7 @@ CheckPointLogicalRewriteHeap(void)
 	cutoff = ReplicationSlotsComputeLogicalRestartLSN();
 
 	/* don't start earlier than the restart lsn */
-	if (cutoff != InvalidXLogRecPtr && redo < cutoff)
+	if (XLogRecPtrIsValid(cutoff) && redo < cutoff)
 		cutoff = redo;
 
 	mappings_dir = AllocateDir(PG_LOGICAL_MAPPINGS_DIR);
@@ -1204,7 +1204,7 @@ CheckPointLogicalRewriteHeap(void)
 
 		lsn = ((uint64) hi) << 32 | lo;
 
-		if (lsn < cutoff || cutoff == InvalidXLogRecPtr)
+		if (lsn < cutoff || !XLogRecPtrIsValid(cutoff))
 		{
 			elog(DEBUG1, "removing logical rewrite file \"%s\"", path);
 			if (unlink(path) < 0)
diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c
index 61fe623cc60..deb9a3dc0d1 100644
--- a/src/backend/access/heap/vacuumlazy.c
+++ b/src/backend/access/heap/vacuumlazy.c
@@ -1901,7 +1901,7 @@ lazy_scan_new_or_empty(LVRelState *vacrel, Buffer buf, BlockNumber blkno,
 			 * WAL-logged, and if not, do that now.
 			 */
 			if (RelationNeedsWAL(vacrel->rel) &&
-				PageGetLSN(page) == InvalidXLogRecPtr)
+				!XLogRecPtrIsValid(PageGetLSN(page)))
 				log_newpage_buffer(buf, true);
 
 			PageSetAllVisible(page);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 8a92b292e56..89d0bfa7760 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -2198,7 +2198,7 @@ ProcessTwoPhaseBuffer(FullTransactionId fxid,
 	Assert(LWLockHeldByMeInMode(TwoPhaseStateLock, LW_EXCLUSIVE));
 
 	if (!fromdisk)
-		Assert(prepare_start_lsn != InvalidXLogRecPtr);
+		Assert(XLogRecPtrIsValid(prepare_start_lsn));
 
 	/* Already processed? */
 	if (TransactionIdDidCommit(XidFromFullTransactionId(fxid)) ||
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 0564482cda8..101b616b028 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -849,7 +849,7 @@ XLogInsertRecord(XLogRecData *rdata,
 
 		if (doPageWrites &&
 			(!prevDoPageWrites ||
-			 (fpw_lsn != InvalidXLogRecPtr && fpw_lsn <= RedoRecPtr)))
+			 (XLogRecPtrIsValid(fpw_lsn) && fpw_lsn <= RedoRecPtr)))
 		{
 			/*
 			 * Oops, some buffer now needs to be backed up that the caller
@@ -883,7 +883,7 @@ XLogInsertRecord(XLogRecData *rdata,
 		 * Those checks are only needed for records that can contain buffer
 		 * references, and an XLOG_SWITCH record never does.
 		 */
-		Assert(fpw_lsn == InvalidXLogRecPtr);
+		Assert(!XLogRecPtrIsValid(fpw_lsn));
 		WALInsertLockAcquireExclusive();
 		inserted = ReserveXLogSwitch(&StartPos, &EndPos, &rechdr->xl_prev);
 	}
@@ -898,7 +898,7 @@ XLogInsertRecord(XLogRecData *rdata,
 		 * not check RedoRecPtr before inserting the record; we just need to
 		 * update it afterwards.
 		 */
-		Assert(fpw_lsn == InvalidXLogRecPtr);
+		Assert(!XLogRecPtrIsValid(fpw_lsn));
 		WALInsertLockAcquireExclusive();
 		ReserveXLogInsertLocation(rechdr->xl_tot_len, &StartPos, &EndPos,
 								  &rechdr->xl_prev);
@@ -1603,7 +1603,7 @@ WaitXLogInsertionsToFinish(XLogRecPtr upto)
 			 */
 		} while (insertingat < upto);
 
-		if (insertingat != InvalidXLogRecPtr && insertingat < finishedUpto)
+		if (XLogRecPtrIsValid(insertingat) && insertingat < finishedUpto)
 			finishedUpto = insertingat;
 	}
 
@@ -7363,7 +7363,7 @@ CreateCheckPoint(int flags)
 	 * Update the average distance between checkpoints if the prior checkpoint
 	 * exists.
 	 */
-	if (PriorRedoPtr != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(PriorRedoPtr))
 		UpdateCheckPointDistanceEstimate(RedoRecPtr - PriorRedoPtr);
 
 	INJECTION_POINT("checkpoint-before-old-wal-removal", NULL);
@@ -7811,7 +7811,7 @@ CreateRestartPoint(int flags)
 	 * Update the average distance between checkpoints/restartpoints if the
 	 * prior checkpoint exists.
 	 */
-	if (PriorRedoPtr != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(PriorRedoPtr))
 		UpdateCheckPointDistanceEstimate(RedoRecPtr - PriorRedoPtr);
 
 	/*
@@ -8018,7 +8018,7 @@ KeepLogSeg(XLogRecPtr recptr, XLogSegNo *logSegNo)
 
 	/* Calculate how many segments are kept by slots. */
 	keep = XLogGetReplicationSlotMinimumLSN();
-	if (keep != InvalidXLogRecPtr && keep < recptr)
+	if (XLogRecPtrIsValid(keep) && keep < recptr)
 	{
 		XLByteToSeg(keep, segno, wal_segment_size);
 
@@ -8045,7 +8045,7 @@ KeepLogSeg(XLogRecPtr recptr, XLogSegNo *logSegNo)
 	 * summarized.
 	 */
 	keep = GetOldestUnsummarizedLSN(NULL, NULL);
-	if (keep != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(keep))
 	{
 		XLogSegNo	unsummarized_segno;
 
@@ -8603,7 +8603,7 @@ xlog_redo(XLogReaderState *record)
 			LocalMinRecoveryPoint = ControlFile->minRecoveryPoint;
 			LocalMinRecoveryPointTLI = ControlFile->minRecoveryPointTLI;
 		}
-		if (LocalMinRecoveryPoint != InvalidXLogRecPtr && LocalMinRecoveryPoint < lsn)
+		if (XLogRecPtrIsValid(LocalMinRecoveryPoint) && LocalMinRecoveryPoint < lsn)
 		{
 			TimeLineID	replayTLI;
 
diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c
index 58cb4b1b00c..a56d5a55282 100644
--- a/src/backend/access/transam/xloginsert.c
+++ b/src/backend/access/transam/xloginsert.c
@@ -528,7 +528,7 @@ XLogInsert(RmgrId rmid, uint8 info)
 
 		EndPos = XLogInsertRecord(rdt, fpw_lsn, curinsert_flags, num_fpi,
 								  fpi_bytes, topxid_included);
-	} while (EndPos == InvalidXLogRecPtr);
+	} while (!XLogRecPtrIsValid(EndPos));
 
 	XLogResetInsertion();
 
@@ -639,7 +639,7 @@ XLogRecordAssemble(RmgrId rmid, uint8 info,
 			needs_backup = (page_lsn <= RedoRecPtr);
 			if (!needs_backup)
 			{
-				if (*fpw_lsn == InvalidXLogRecPtr || page_lsn < *fpw_lsn)
+				if (!XLogRecPtrIsValid(*fpw_lsn) || page_lsn < *fpw_lsn)
 					*fpw_lsn = page_lsn;
 			}
 		}
diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index aad16127e60..755f351143a 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -558,7 +558,7 @@ XLogDecodeNextRecord(XLogReaderState *state, bool nonblocking)
 
 	RecPtr = state->NextRecPtr;
 
-	if (state->DecodeRecPtr != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(state->DecodeRecPtr))
 	{
 		/* read the record after the one we just read */
 
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index bb7b79613c2..b4ed57b0864 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -758,9 +758,9 @@ InitWalRecovery(ControlFileData *ControlFile, bool *wasShutdown_ptr,
 		 * end-of-backup record), and we can enter archive recovery directly.
 		 */
 		if (ArchiveRecoveryRequested &&
-			(ControlFile->minRecoveryPoint != InvalidXLogRecPtr ||
+			(XLogRecPtrIsValid(ControlFile->minRecoveryPoint) ||
 			 ControlFile->backupEndRequired ||
-			 ControlFile->backupEndPoint != InvalidXLogRecPtr ||
+			 XLogRecPtrIsValid(ControlFile->backupEndPoint) ||
 			 ControlFile->state == DB_SHUTDOWNED))
 		{
 			InArchiveRecovery = true;
@@ -3164,7 +3164,7 @@ ReadRecord(XLogPrefetcher *xlogprefetcher, int emode,
 	/* Pass through parameters to XLogPageRead */
 	private->fetching_ckpt = fetching_ckpt;
 	private->emode = emode;
-	private->randAccess = (xlogreader->ReadRecPtr == InvalidXLogRecPtr);
+	private->randAccess = (!XLogRecPtrIsValid(xlogreader->ReadRecPtr));
 	private->replayTLI = replayTLI;
 
 	/* This is the first attempt to read this page. */
@@ -4370,7 +4370,7 @@ XLogFileReadAnyTLI(XLogSegNo segno, XLogSource source)
 		 * Skip scanning the timeline ID that the logfile segment to read
 		 * doesn't belong to
 		 */
-		if (hent->begin != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(hent->begin))
 		{
 			XLogSegNo	beginseg = 0;
 
diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c
index 38176d9688e..ce2a3e42146 100644
--- a/src/backend/access/transam/xlogutils.c
+++ b/src/backend/access/transam/xlogutils.c
@@ -710,7 +710,7 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage,
 	const XLogRecPtr lastReadPage = (state->seg.ws_segno *
 									 state->segcxt.ws_segsize + state->segoff);
 
-	Assert(wantPage != InvalidXLogRecPtr && wantPage % XLOG_BLCKSZ == 0);
+	Assert(XLogRecPtrIsValid(wantPage) && wantPage % XLOG_BLCKSZ == 0);
 	Assert(wantLength <= XLOG_BLCKSZ);
 	Assert(state->readLen == 0 || state->readLen <= XLOG_BLCKSZ);
 	Assert(currTLI != 0);
@@ -741,7 +741,7 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage,
 	 */
 	if (state->currTLI == currTLI && wantPage >= lastReadPage)
 	{
-		Assert(state->currTLIValidUntil == InvalidXLogRecPtr);
+		Assert(!XLogRecPtrIsValid(state->currTLIValidUntil));
 		return;
 	}
 
@@ -750,7 +750,7 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage,
 	 * timeline and the timeline we're reading from is valid until the end of
 	 * the current segment we can just keep reading.
 	 */
-	if (state->currTLIValidUntil != InvalidXLogRecPtr &&
+	if (XLogRecPtrIsValid(state->currTLIValidUntil) &&
 		state->currTLI != currTLI &&
 		state->currTLI != 0 &&
 		((wantPage + wantLength) / state->segcxt.ws_segsize) <
@@ -790,7 +790,7 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage,
 		state->currTLIValidUntil = tliSwitchPoint(state->currTLI, timelineHistory,
 												  &state->nextTLI);
 
-		Assert(state->currTLIValidUntil == InvalidXLogRecPtr ||
+		Assert(!XLogRecPtrIsValid(state->currTLIValidUntil) ||
 			   wantPage + wantLength < state->currTLIValidUntil);
 
 		list_free_deep(timelineHistory);
diff --git a/src/backend/catalog/pg_subscription.c b/src/backend/catalog/pg_subscription.c
index 1945627ed88..180e77e9484 100644
--- a/src/backend/catalog/pg_subscription.c
+++ b/src/backend/catalog/pg_subscription.c
@@ -293,7 +293,7 @@ AddSubscriptionRelState(Oid subid, Oid relid, char state,
 	values[Anum_pg_subscription_rel_srsubid - 1] = ObjectIdGetDatum(subid);
 	values[Anum_pg_subscription_rel_srrelid - 1] = ObjectIdGetDatum(relid);
 	values[Anum_pg_subscription_rel_srsubstate - 1] = CharGetDatum(state);
-	if (sublsn != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(sublsn))
 		values[Anum_pg_subscription_rel_srsublsn - 1] = LSNGetDatum(sublsn);
 	else
 		nulls[Anum_pg_subscription_rel_srsublsn - 1] = true;
@@ -366,7 +366,7 @@ UpdateSubscriptionRelState(Oid subid, Oid relid, char state,
 	values[Anum_pg_subscription_rel_srsubstate - 1] = CharGetDatum(state);
 
 	replaces[Anum_pg_subscription_rel_srsublsn - 1] = true;
-	if (sublsn != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(sublsn))
 		values[Anum_pg_subscription_rel_srsublsn - 1] = LSNGetDatum(sublsn);
 	else
 		nulls[Anum_pg_subscription_rel_srsublsn - 1] = true;
diff --git a/src/backend/replication/logical/logical.c b/src/backend/replication/logical/logical.c
index 79717b52941..866f92cf799 100644
--- a/src/backend/replication/logical/logical.c
+++ b/src/backend/replication/logical/logical.c
@@ -546,9 +546,9 @@ CreateDecodingContext(XLogRecPtr start_lsn,
 
 	/* slot must be valid to allow decoding */
 	Assert(slot->data.invalidated == RS_INVAL_NONE);
-	Assert(slot->data.restart_lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(slot->data.restart_lsn));
 
-	if (start_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(start_lsn))
 	{
 		/* continue from last position */
 		start_lsn = slot->data.confirmed_flush;
@@ -757,7 +757,7 @@ output_plugin_error_callback(void *arg)
 	LogicalErrorCallbackState *state = (LogicalErrorCallbackState *) arg;
 
 	/* not all callbacks have an associated LSN  */
-	if (state->report_location != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(state->report_location))
 		errcontext("slot \"%s\", output plugin \"%s\", in the %s callback, associated LSN %X/%08X",
 				   NameStr(state->ctx->slot->data.name),
 				   NameStr(state->ctx->slot->data.plugin),
@@ -1711,7 +1711,7 @@ LogicalIncreaseXminForSlot(XLogRecPtr current_lsn, TransactionId xmin)
 	 * Only increase if the previous values have been applied, otherwise we
 	 * might never end up updating if the receiver acks too slowly.
 	 */
-	else if (slot->candidate_xmin_lsn == InvalidXLogRecPtr)
+	else if (!XLogRecPtrIsValid(slot->candidate_xmin_lsn))
 	{
 		slot->candidate_catalog_xmin = xmin;
 		slot->candidate_xmin_lsn = current_lsn;
@@ -1749,8 +1749,8 @@ LogicalIncreaseRestartDecodingForSlot(XLogRecPtr current_lsn, XLogRecPtr restart
 	slot = MyReplicationSlot;
 
 	Assert(slot != NULL);
-	Assert(restart_lsn != InvalidXLogRecPtr);
-	Assert(current_lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(restart_lsn));
+	Assert(XLogRecPtrIsValid(current_lsn));
 
 	SpinLockAcquire(&slot->mutex);
 
@@ -1779,7 +1779,7 @@ LogicalIncreaseRestartDecodingForSlot(XLogRecPtr current_lsn, XLogRecPtr restart
 	 * might never end up updating if the receiver acks too slowly. A missed
 	 * value here will just cause some extra effort after reconnecting.
 	 */
-	else if (slot->candidate_restart_valid == InvalidXLogRecPtr)
+	else if (!XLogRecPtrIsValid(slot->candidate_restart_valid))
 	{
 		slot->candidate_restart_valid = current_lsn;
 		slot->candidate_restart_lsn = restart_lsn;
@@ -1819,11 +1819,11 @@ LogicalIncreaseRestartDecodingForSlot(XLogRecPtr current_lsn, XLogRecPtr restart
 void
 LogicalConfirmReceivedLocation(XLogRecPtr lsn)
 {
-	Assert(lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(lsn));
 
 	/* Do an unlocked check for candidate_lsn first. */
-	if (MyReplicationSlot->candidate_xmin_lsn != InvalidXLogRecPtr ||
-		MyReplicationSlot->candidate_restart_valid != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(MyReplicationSlot->candidate_xmin_lsn) ||
+		XLogRecPtrIsValid(MyReplicationSlot->candidate_restart_valid))
 	{
 		bool		updated_xmin = false;
 		bool		updated_restart = false;
@@ -1849,7 +1849,7 @@ LogicalConfirmReceivedLocation(XLogRecPtr lsn)
 			MyReplicationSlot->data.confirmed_flush = lsn;
 
 		/* if we're past the location required for bumping xmin, do so */
-		if (MyReplicationSlot->candidate_xmin_lsn != InvalidXLogRecPtr &&
+		if (XLogRecPtrIsValid(MyReplicationSlot->candidate_xmin_lsn) &&
 			MyReplicationSlot->candidate_xmin_lsn <= lsn)
 		{
 			/*
@@ -1871,10 +1871,10 @@ LogicalConfirmReceivedLocation(XLogRecPtr lsn)
 			}
 		}
 
-		if (MyReplicationSlot->candidate_restart_valid != InvalidXLogRecPtr &&
+		if (XLogRecPtrIsValid(MyReplicationSlot->candidate_restart_valid) &&
 			MyReplicationSlot->candidate_restart_valid <= lsn)
 		{
-			Assert(MyReplicationSlot->candidate_restart_lsn != InvalidXLogRecPtr);
+			Assert(XLogRecPtrIsValid(MyReplicationSlot->candidate_restart_lsn));
 
 			MyReplicationSlot->data.restart_lsn = MyReplicationSlot->candidate_restart_lsn;
 			MyReplicationSlot->candidate_restart_lsn = InvalidXLogRecPtr;
@@ -2089,7 +2089,7 @@ LogicalSlotAdvanceAndCheckSnapState(XLogRecPtr moveto,
 	ResourceOwner old_resowner PG_USED_FOR_ASSERTS_ONLY = CurrentResourceOwner;
 	XLogRecPtr	retlsn;
 
-	Assert(moveto != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(moveto));
 
 	if (found_consistent_snapshot)
 		*found_consistent_snapshot = false;
@@ -2163,7 +2163,7 @@ LogicalSlotAdvanceAndCheckSnapState(XLogRecPtr moveto,
 		if (found_consistent_snapshot && DecodingContextReady(ctx))
 			*found_consistent_snapshot = true;
 
-		if (ctx->reader->EndRecPtr != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(ctx->reader->EndRecPtr))
 		{
 			LogicalConfirmReceivedLocation(moveto);
 
diff --git a/src/backend/replication/logical/logicalfuncs.c b/src/backend/replication/logical/logicalfuncs.c
index d78e486bca6..49b2aef3c74 100644
--- a/src/backend/replication/logical/logicalfuncs.c
+++ b/src/backend/replication/logical/logicalfuncs.c
@@ -276,7 +276,7 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin
 			}
 
 			/* check limits */
-			if (upto_lsn != InvalidXLogRecPtr &&
+			if (XLogRecPtrIsValid(upto_lsn) &&
 				upto_lsn <= ctx->reader->EndRecPtr)
 				break;
 			if (upto_nchanges != 0 &&
@@ -289,7 +289,7 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin
 		 * Next time, start where we left off. (Hunting things, the family
 		 * business..)
 		 */
-		if (ctx->reader->EndRecPtr != InvalidXLogRecPtr && confirm)
+		if (XLogRecPtrIsValid(ctx->reader->EndRecPtr) && confirm)
 		{
 			LogicalConfirmReceivedLocation(ctx->reader->EndRecPtr);
 
diff --git a/src/backend/replication/logical/origin.c b/src/backend/replication/logical/origin.c
index bcd5d9aad62..4632aa8115d 100644
--- a/src/backend/replication/logical/origin.c
+++ b/src/backend/replication/logical/origin.c
@@ -984,8 +984,8 @@ replorigin_advance(RepOriginId node,
 		/* initialize new slot */
 		LWLockAcquire(&free_state->lock, LW_EXCLUSIVE);
 		replication_state = free_state;
-		Assert(replication_state->remote_lsn == InvalidXLogRecPtr);
-		Assert(replication_state->local_lsn == InvalidXLogRecPtr);
+		Assert(!XLogRecPtrIsValid(replication_state->remote_lsn));
+		Assert(!XLogRecPtrIsValid(replication_state->local_lsn));
 		replication_state->roident = node;
 	}
 
@@ -1020,7 +1020,7 @@ replorigin_advance(RepOriginId node,
 	 */
 	if (go_backward || replication_state->remote_lsn < remote_commit)
 		replication_state->remote_lsn = remote_commit;
-	if (local_commit != InvalidXLogRecPtr &&
+	if (XLogRecPtrIsValid(local_commit) &&
 		(go_backward || replication_state->local_lsn < local_commit))
 		replication_state->local_lsn = local_commit;
 	LWLockRelease(&replication_state->lock);
@@ -1064,7 +1064,7 @@ replorigin_get_progress(RepOriginId node, bool flush)
 
 	LWLockRelease(ReplicationOriginLock);
 
-	if (flush && local_lsn != InvalidXLogRecPtr)
+	if (flush && XLogRecPtrIsValid(local_lsn))
 		XLogFlush(local_lsn);
 
 	return remote_lsn;
@@ -1197,8 +1197,8 @@ replorigin_session_setup(RepOriginId node, int acquired_by)
 
 		/* initialize new slot */
 		session_replication_state = &replication_states[free_slot];
-		Assert(session_replication_state->remote_lsn == InvalidXLogRecPtr);
-		Assert(session_replication_state->local_lsn == InvalidXLogRecPtr);
+		Assert(!XLogRecPtrIsValid(session_replication_state->remote_lsn));
+		Assert(!XLogRecPtrIsValid(session_replication_state->local_lsn));
 		session_replication_state->roident = node;
 	}
 
@@ -1282,7 +1282,7 @@ replorigin_session_get_progress(bool flush)
 	local_lsn = session_replication_state->local_lsn;
 	LWLockRelease(&session_replication_state->lock);
 
-	if (flush && local_lsn != InvalidXLogRecPtr)
+	if (flush && XLogRecPtrIsValid(local_lsn))
 		XLogFlush(local_lsn);
 
 	return remote_lsn;
@@ -1454,7 +1454,7 @@ pg_replication_origin_session_progress(PG_FUNCTION_ARGS)
 
 	remote_lsn = replorigin_session_get_progress(flush);
 
-	if (remote_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(remote_lsn))
 		PG_RETURN_NULL();
 
 	PG_RETURN_LSN(remote_lsn);
@@ -1543,7 +1543,7 @@ pg_replication_origin_progress(PG_FUNCTION_ARGS)
 
 	remote_lsn = replorigin_get_progress(roident, flush);
 
-	if (remote_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(remote_lsn))
 		PG_RETURN_NULL();
 
 	PG_RETURN_LSN(remote_lsn);
diff --git a/src/backend/replication/logical/proto.c b/src/backend/replication/logical/proto.c
index ed62888764c..f0a913892b9 100644
--- a/src/backend/replication/logical/proto.c
+++ b/src/backend/replication/logical/proto.c
@@ -64,7 +64,7 @@ logicalrep_read_begin(StringInfo in, LogicalRepBeginData *begin_data)
 {
 	/* read fields */
 	begin_data->final_lsn = pq_getmsgint64(in);
-	if (begin_data->final_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(begin_data->final_lsn))
 		elog(ERROR, "final_lsn not set in begin message");
 	begin_data->committime = pq_getmsgint64(in);
 	begin_data->xid = pq_getmsgint(in, 4);
@@ -135,10 +135,10 @@ logicalrep_read_begin_prepare(StringInfo in, LogicalRepPreparedTxnData *begin_da
 {
 	/* read fields */
 	begin_data->prepare_lsn = pq_getmsgint64(in);
-	if (begin_data->prepare_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(begin_data->prepare_lsn))
 		elog(ERROR, "prepare_lsn not set in begin prepare message");
 	begin_data->end_lsn = pq_getmsgint64(in);
-	if (begin_data->end_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(begin_data->end_lsn))
 		elog(ERROR, "end_lsn not set in begin prepare message");
 	begin_data->prepare_time = pq_getmsgint64(in);
 	begin_data->xid = pq_getmsgint(in, 4);
@@ -207,10 +207,10 @@ logicalrep_read_prepare_common(StringInfo in, char *msgtype,
 
 	/* read fields */
 	prepare_data->prepare_lsn = pq_getmsgint64(in);
-	if (prepare_data->prepare_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(prepare_data->prepare_lsn))
 		elog(ERROR, "prepare_lsn is not set in %s message", msgtype);
 	prepare_data->end_lsn = pq_getmsgint64(in);
-	if (prepare_data->end_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(prepare_data->end_lsn))
 		elog(ERROR, "end_lsn is not set in %s message", msgtype);
 	prepare_data->prepare_time = pq_getmsgint64(in);
 	prepare_data->xid = pq_getmsgint(in, 4);
@@ -274,10 +274,10 @@ logicalrep_read_commit_prepared(StringInfo in, LogicalRepCommitPreparedTxnData *
 
 	/* read fields */
 	prepare_data->commit_lsn = pq_getmsgint64(in);
-	if (prepare_data->commit_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(prepare_data->commit_lsn))
 		elog(ERROR, "commit_lsn is not set in commit prepared message");
 	prepare_data->end_lsn = pq_getmsgint64(in);
-	if (prepare_data->end_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(prepare_data->end_lsn))
 		elog(ERROR, "end_lsn is not set in commit prepared message");
 	prepare_data->commit_time = pq_getmsgint64(in);
 	prepare_data->xid = pq_getmsgint(in, 4);
@@ -333,10 +333,10 @@ logicalrep_read_rollback_prepared(StringInfo in,
 
 	/* read fields */
 	rollback_data->prepare_end_lsn = pq_getmsgint64(in);
-	if (rollback_data->prepare_end_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(rollback_data->prepare_end_lsn))
 		elog(ERROR, "prepare_end_lsn is not set in rollback prepared message");
 	rollback_data->rollback_end_lsn = pq_getmsgint64(in);
-	if (rollback_data->rollback_end_lsn == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(rollback_data->rollback_end_lsn))
 		elog(ERROR, "rollback_end_lsn is not set in rollback prepared message");
 	rollback_data->prepare_time = pq_getmsgint64(in);
 	rollback_data->rollback_time = pq_getmsgint64(in);
diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c
index b57aef9916d..eb6a84554b7 100644
--- a/src/backend/replication/logical/reorderbuffer.c
+++ b/src/backend/replication/logical/reorderbuffer.c
@@ -701,7 +701,7 @@ ReorderBufferTXNByXid(ReorderBuffer *rb, TransactionId xid, bool create,
 	{
 		/* initialize the new entry, if creation was requested */
 		Assert(ent != NULL);
-		Assert(lsn != InvalidXLogRecPtr);
+		Assert(XLogRecPtrIsValid(lsn));
 
 		ent->txn = ReorderBufferAllocTXN(rb);
 		ent->txn->xid = xid;
@@ -849,7 +849,7 @@ ReorderBufferQueueChange(ReorderBuffer *rb, TransactionId xid, XLogRecPtr lsn,
 	change->lsn = lsn;
 	change->txn = txn;
 
-	Assert(InvalidXLogRecPtr != lsn);
+	Assert(XLogRecPtrIsValid(lsn));
 	dlist_push_tail(&txn->changes, &change->node);
 	txn->nentries++;
 	txn->nentries_mem++;
@@ -966,14 +966,14 @@ AssertTXNLsnOrder(ReorderBuffer *rb)
 													iter.cur);
 
 		/* start LSN must be set */
-		Assert(cur_txn->first_lsn != InvalidXLogRecPtr);
+		Assert(XLogRecPtrIsValid(cur_txn->first_lsn));
 
 		/* If there is an end LSN, it must be higher than start LSN */
-		if (cur_txn->end_lsn != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(cur_txn->end_lsn))
 			Assert(cur_txn->first_lsn <= cur_txn->end_lsn);
 
 		/* Current initial LSN must be strictly higher than previous */
-		if (prev_first_lsn != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(prev_first_lsn))
 			Assert(prev_first_lsn < cur_txn->first_lsn);
 
 		/* known-as-subtxn txns must not be listed */
@@ -990,10 +990,10 @@ AssertTXNLsnOrder(ReorderBuffer *rb)
 
 		/* base snapshot (and its LSN) must be set */
 		Assert(cur_txn->base_snapshot != NULL);
-		Assert(cur_txn->base_snapshot_lsn != InvalidXLogRecPtr);
+		Assert(XLogRecPtrIsValid(cur_txn->base_snapshot_lsn));
 
 		/* current LSN must be strictly higher than previous */
-		if (prev_base_snap_lsn != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(prev_base_snap_lsn))
 			Assert(prev_base_snap_lsn < cur_txn->base_snapshot_lsn);
 
 		/* known-as-subtxn txns must not be listed */
@@ -1022,11 +1022,11 @@ AssertChangeLsnOrder(ReorderBufferTXN *txn)
 
 		cur_change = dlist_container(ReorderBufferChange, node, iter.cur);
 
-		Assert(txn->first_lsn != InvalidXLogRecPtr);
-		Assert(cur_change->lsn != InvalidXLogRecPtr);
+		Assert(XLogRecPtrIsValid(txn->first_lsn));
+		Assert(XLogRecPtrIsValid(cur_change->lsn));
 		Assert(txn->first_lsn <= cur_change->lsn);
 
-		if (txn->end_lsn != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(txn->end_lsn))
 			Assert(cur_change->lsn <= txn->end_lsn);
 
 		Assert(prev_lsn <= cur_change->lsn);
@@ -1053,7 +1053,7 @@ ReorderBufferGetOldestTXN(ReorderBuffer *rb)
 	txn = dlist_head_element(ReorderBufferTXN, node, &rb->toplevel_by_lsn);
 
 	Assert(!rbtxn_is_known_subxact(txn));
-	Assert(txn->first_lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(txn->first_lsn));
 	return txn;
 }
 
@@ -2276,7 +2276,7 @@ ReorderBufferProcessTXN(ReorderBuffer *rb, ReorderBufferTXN *txn,
 			 * We can't call start stream callback before processing first
 			 * change.
 			 */
-			if (prev_lsn == InvalidXLogRecPtr)
+			if (!XLogRecPtrIsValid(prev_lsn))
 			{
 				if (streaming)
 				{
@@ -2291,7 +2291,7 @@ ReorderBufferProcessTXN(ReorderBuffer *rb, ReorderBufferTXN *txn,
 			 * subtransactions. The changes may have the same LSN due to
 			 * MULTI_INSERT xlog records.
 			 */
-			Assert(prev_lsn == InvalidXLogRecPtr || prev_lsn <= change->lsn);
+			Assert(!XLogRecPtrIsValid(prev_lsn) || prev_lsn <= change->lsn);
 
 			prev_lsn = change->lsn;
 
@@ -2975,7 +2975,7 @@ ReorderBufferPrepare(ReorderBuffer *rb, TransactionId xid,
 	 * have been updated in it by now.
 	 */
 	Assert((txn->txn_flags & RBTXN_PREPARE_STATUS_MASK) == RBTXN_IS_PREPARED);
-	Assert(txn->final_lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(txn->final_lsn));
 
 	txn->gid = pstrdup(gid);
 
@@ -3041,7 +3041,7 @@ ReorderBufferFinishPrepared(ReorderBuffer *rb, TransactionId xid,
 		 */
 		Assert((txn->txn_flags & RBTXN_PREPARE_STATUS_MASK) ==
 			   (RBTXN_IS_PREPARED | RBTXN_SKIPPED_PREPARE));
-		Assert(txn->final_lsn != InvalidXLogRecPtr);
+		Assert(XLogRecPtrIsValid(txn->final_lsn));
 
 		/*
 		 * By this time the txn has the prepare record information and it is
@@ -4552,8 +4552,8 @@ ReorderBufferRestoreChanges(ReorderBuffer *rb, ReorderBufferTXN *txn,
 	dlist_mutable_iter cleanup_iter;
 	File	   *fd = &file->vfd;
 
-	Assert(txn->first_lsn != InvalidXLogRecPtr);
-	Assert(txn->final_lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(txn->first_lsn));
+	Assert(XLogRecPtrIsValid(txn->final_lsn));
 
 	/* free current entries, so we have memory for more */
 	dlist_foreach_modify(cleanup_iter, &txn->changes)
@@ -4860,8 +4860,8 @@ ReorderBufferRestoreCleanup(ReorderBuffer *rb, ReorderBufferTXN *txn)
 	XLogSegNo	cur;
 	XLogSegNo	last;
 
-	Assert(txn->first_lsn != InvalidXLogRecPtr);
-	Assert(txn->final_lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(txn->first_lsn));
+	Assert(XLogRecPtrIsValid(txn->final_lsn));
 
 	XLByteToSeg(txn->first_lsn, first, wal_segment_size);
 	XLByteToSeg(txn->final_lsn, last, wal_segment_size);
diff --git a/src/backend/replication/logical/snapbuild.c b/src/backend/replication/logical/snapbuild.c
index 98ddee20929..6e18baa33cb 100644
--- a/src/backend/replication/logical/snapbuild.c
+++ b/src/backend/replication/logical/snapbuild.c
@@ -1210,7 +1210,7 @@ SnapBuildProcessRunningXacts(SnapBuild *builder, XLogRecPtr lsn, xl_running_xact
 	 * oldest ongoing txn might have started when we didn't yet serialize
 	 * anything because we hadn't reached a consistent state yet.
 	 */
-	if (txn != NULL && txn->restart_decoding_lsn != InvalidXLogRecPtr)
+	if (txn != NULL && XLogRecPtrIsValid(txn->restart_decoding_lsn))
 		LogicalIncreaseRestartDecodingForSlot(lsn, txn->restart_decoding_lsn);
 
 	/*
@@ -1218,8 +1218,8 @@ SnapBuildProcessRunningXacts(SnapBuild *builder, XLogRecPtr lsn, xl_running_xact
 	 * we have one.
 	 */
 	else if (txn == NULL &&
-			 builder->reorder->current_restart_decoding_lsn != InvalidXLogRecPtr &&
-			 builder->last_serialized_snapshot != InvalidXLogRecPtr)
+			 XLogRecPtrIsValid(builder->reorder->current_restart_decoding_lsn) &&
+			 XLogRecPtrIsValid(builder->last_serialized_snapshot))
 		LogicalIncreaseRestartDecodingForSlot(lsn,
 											  builder->last_serialized_snapshot);
 }
@@ -1293,7 +1293,7 @@ SnapBuildFindSnapshot(SnapBuild *builder, XLogRecPtr lsn, xl_running_xacts *runn
 	 */
 	if (running->oldestRunningXid == running->nextXid)
 	{
-		if (builder->start_decoding_at == InvalidXLogRecPtr ||
+		if (!XLogRecPtrIsValid(builder->start_decoding_at) ||
 			builder->start_decoding_at <= lsn)
 			/* can decode everything after this */
 			builder->start_decoding_at = lsn + 1;
@@ -1509,8 +1509,8 @@ SnapBuildSerialize(SnapBuild *builder, XLogRecPtr lsn)
 	struct stat stat_buf;
 	Size		sz;
 
-	Assert(lsn != InvalidXLogRecPtr);
-	Assert(builder->last_serialized_snapshot == InvalidXLogRecPtr ||
+	Assert(XLogRecPtrIsValid(lsn));
+	Assert(!XLogRecPtrIsValid(builder->last_serialized_snapshot) ||
 		   builder->last_serialized_snapshot <= lsn);
 
 	/*
@@ -2029,7 +2029,7 @@ CheckPointSnapBuild(void)
 		lsn = ((uint64) hi) << 32 | lo;
 
 		/* check whether we still need it */
-		if (lsn < cutoff || cutoff == InvalidXLogRecPtr)
+		if (lsn < cutoff || !XLogRecPtrIsValid(cutoff))
 		{
 			elog(DEBUG1, "removing snapbuild snapshot %s", path);
 
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index 0cb93dc90f2..1ec1e997b27 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -1270,15 +1270,15 @@ ReplicationSlotsComputeRequiredLSN(void)
 		 */
 		if (persistency == RS_PERSISTENT)
 		{
-			if (last_saved_restart_lsn != InvalidXLogRecPtr &&
+			if (XLogRecPtrIsValid(last_saved_restart_lsn) &&
 				restart_lsn > last_saved_restart_lsn)
 			{
 				restart_lsn = last_saved_restart_lsn;
 			}
 		}
 
-		if (restart_lsn != InvalidXLogRecPtr &&
-			(min_required == InvalidXLogRecPtr ||
+		if (XLogRecPtrIsValid(restart_lsn) &&
+			(!XLogRecPtrIsValid(min_required) ||
 			 restart_lsn < min_required))
 			min_required = restart_lsn;
 	}
@@ -1350,17 +1350,17 @@ ReplicationSlotsComputeLogicalRestartLSN(void)
 		 */
 		if (persistency == RS_PERSISTENT)
 		{
-			if (last_saved_restart_lsn != InvalidXLogRecPtr &&
+			if (XLogRecPtrIsValid(last_saved_restart_lsn) &&
 				restart_lsn > last_saved_restart_lsn)
 			{
 				restart_lsn = last_saved_restart_lsn;
 			}
 		}
 
-		if (restart_lsn == InvalidXLogRecPtr)
+		if (!XLogRecPtrIsValid(restart_lsn))
 			continue;
 
-		if (result == InvalidXLogRecPtr ||
+		if (!XLogRecPtrIsValid(result) ||
 			restart_lsn < result)
 			result = restart_lsn;
 	}
@@ -1573,8 +1573,8 @@ ReplicationSlotReserveWal(void)
 	ReplicationSlot *slot = MyReplicationSlot;
 
 	Assert(slot != NULL);
-	Assert(slot->data.restart_lsn == InvalidXLogRecPtr);
-	Assert(slot->last_saved_restart_lsn == InvalidXLogRecPtr);
+	Assert(!XLogRecPtrIsValid(slot->data.restart_lsn));
+	Assert(!XLogRecPtrIsValid(slot->last_saved_restart_lsn));
 
 	/*
 	 * The replication slot mechanism is used to prevent removal of required
@@ -1754,7 +1754,7 @@ DetermineSlotInvalidationCause(uint32 possible_causes, ReplicationSlot *s,
 	{
 		XLogRecPtr	restart_lsn = s->data.restart_lsn;
 
-		if (restart_lsn != InvalidXLogRecPtr &&
+		if (XLogRecPtrIsValid(restart_lsn) &&
 			restart_lsn < oldestLSN)
 			return RS_INVAL_WAL_REMOVED;
 	}
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 5aecd5c6a50..0478fc9c977 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -308,12 +308,12 @@ pg_get_replication_slots(PG_FUNCTION_ARGS)
 		else
 			nulls[i++] = true;
 
-		if (slot_contents.data.restart_lsn != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(slot_contents.data.restart_lsn))
 			values[i++] = LSNGetDatum(slot_contents.data.restart_lsn);
 		else
 			nulls[i++] = true;
 
-		if (slot_contents.data.confirmed_flush != InvalidXLogRecPtr)
+		if (XLogRecPtrIsValid(slot_contents.data.confirmed_flush))
 			values[i++] = LSNGetDatum(slot_contents.data.confirmed_flush);
 		else
 			nulls[i++] = true;
@@ -467,7 +467,7 @@ pg_physical_replication_slot_advance(XLogRecPtr moveto)
 	XLogRecPtr	startlsn = MyReplicationSlot->data.restart_lsn;
 	XLogRecPtr	retlsn = startlsn;
 
-	Assert(moveto != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(moveto));
 
 	if (startlsn < moveto)
 	{
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index b6dfb230d0d..4a678e60b74 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -2397,7 +2397,7 @@ PhysicalConfirmReceivedLocation(XLogRecPtr lsn)
 	bool		changed = false;
 	ReplicationSlot *slot = MyReplicationSlot;
 
-	Assert(lsn != InvalidXLogRecPtr);
+	Assert(XLogRecPtrIsValid(lsn));
 	SpinLockAcquire(&slot->mutex);
 	if (slot->data.restart_lsn != lsn)
 	{
@@ -2519,7 +2519,7 @@ ProcessStandbyReplyMessage(void)
 	/*
 	 * Advance our local xmin horizon when the client confirmed a flush.
 	 */
-	if (MyReplicationSlot && flushPtr != InvalidXLogRecPtr)
+	if (MyReplicationSlot && XLogRecPtrIsValid(flushPtr))
 	{
 		if (SlotIsLogical(MyReplicationSlot))
 			LogicalConfirmReceivedLocation(flushPtr);
@@ -3536,7 +3536,7 @@ XLogSendLogical(void)
 	 * If first time through in this session, initialize flushPtr.  Otherwise,
 	 * we only need to update flushPtr if EndRecPtr is past it.
 	 */
-	if (flushPtr == InvalidXLogRecPtr ||
+	if (!XLogRecPtrIsValid(flushPtr) ||
 		logical_decoding_ctx->reader->EndRecPtr >= flushPtr)
 	{
 		/*
diff --git a/src/bin/pg_basebackup/pg_receivewal.c b/src/bin/pg_basebackup/pg_receivewal.c
index 3e6f4a7fc48..46e553dce4b 100644
--- a/src/bin/pg_basebackup/pg_receivewal.c
+++ b/src/bin/pg_basebackup/pg_receivewal.c
@@ -535,7 +535,7 @@ StreamLog(void)
 	 * Figure out where to start streaming.  First scan the local directory.
 	 */
 	stream.startpos = FindStreamingStart(&stream.timeline);
-	if (stream.startpos == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(stream.startpos))
 	{
 		/*
 		 * Try to get the starting point from the slot if any.  This is
@@ -556,14 +556,14 @@ StreamLog(void)
 		 * If it the starting point is still not known, use the current WAL
 		 * flush value as last resort.
 		 */
-		if (stream.startpos == InvalidXLogRecPtr)
+		if (!XLogRecPtrIsValid(stream.startpos))
 		{
 			stream.startpos = serverpos;
 			stream.timeline = servertli;
 		}
 	}
 
-	Assert(stream.startpos != InvalidXLogRecPtr &&
+	Assert(XLogRecPtrIsValid(stream.startpos) &&
 		   stream.timeline != 0);
 
 	/*
diff --git a/src/bin/pg_basebackup/pg_recvlogical.c b/src/bin/pg_basebackup/pg_recvlogical.c
index 6739784a993..14ad1504678 100644
--- a/src/bin/pg_basebackup/pg_recvlogical.c
+++ b/src/bin/pg_basebackup/pg_recvlogical.c
@@ -482,7 +482,7 @@ StreamLogicalLog(void)
 			}
 			replyRequested = copybuf[pos];
 
-			if (endpos != InvalidXLogRecPtr && walEnd >= endpos)
+			if (XLogRecPtrIsValid(endpos) && walEnd >= endpos)
 			{
 				/*
 				 * If there's nothing to read on the socket until a keepalive
@@ -535,7 +535,7 @@ StreamLogicalLog(void)
 		/* Extract WAL location for this block */
 		cur_record_lsn = fe_recvint64(&copybuf[1]);
 
-		if (endpos != InvalidXLogRecPtr && cur_record_lsn > endpos)
+		if (XLogRecPtrIsValid(endpos) && cur_record_lsn > endpos)
 		{
 			/*
 			 * We've read past our endpoint, so prepare to go away being
@@ -583,7 +583,7 @@ StreamLogicalLog(void)
 			goto error;
 		}
 
-		if (endpos != InvalidXLogRecPtr && cur_record_lsn == endpos)
+		if (XLogRecPtrIsValid(endpos) && cur_record_lsn == endpos)
 		{
 			/* endpos was exactly the record we just processed, we're done */
 			if (!flushAndSendFeedback(conn, &now))
@@ -913,14 +913,14 @@ main(int argc, char **argv)
 		exit(1);
 	}
 
-	if (startpos != InvalidXLogRecPtr && (do_create_slot || do_drop_slot))
+	if (XLogRecPtrIsValid(startpos) && (do_create_slot || do_drop_slot))
 	{
 		pg_log_error("cannot use --create-slot or --drop-slot together with --startpos");
 		pg_log_error_hint("Try \"%s --help\" for more information.", progname);
 		exit(1);
 	}
 
-	if (endpos != InvalidXLogRecPtr && !do_start_slot)
+	if (XLogRecPtrIsValid(endpos) && !do_start_slot)
 	{
 		pg_log_error("--endpos may only be specified with --start");
 		pg_log_error_hint("Try \"%s --help\" for more information.", progname);
diff --git a/src/bin/pg_waldump/pg_waldump.c b/src/bin/pg_waldump/pg_waldump.c
index 19cf5461eac..c6d6ba79e44 100644
--- a/src/bin/pg_waldump/pg_waldump.c
+++ b/src/bin/pg_waldump/pg_waldump.c
@@ -393,7 +393,7 @@ WALDumpReadPage(XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen,
 	int			count = XLOG_BLCKSZ;
 	WALReadError errinfo;
 
-	if (private->endptr != InvalidXLogRecPtr)
+	if (XLogRecPtrIsValid(private->endptr))
 	{
 		if (targetPagePtr + XLOG_BLCKSZ <= private->endptr)
 			count = XLOG_BLCKSZ;
@@ -1213,7 +1213,7 @@ main(int argc, char **argv)
 	/* first find a valid recptr to start from */
 	first_record = XLogFindNextRecord(xlogreader_state, private.startptr);
 
-	if (first_record == InvalidXLogRecPtr)
+	if (!XLogRecPtrIsValid(first_record))
 		pg_fatal("could not find a valid record after %X/%08X",
 				 LSN_FORMAT_ARGS(private.startptr));
 
diff --git a/src/include/access/xlogdefs.h b/src/include/access/xlogdefs.h
index b0be7ca3a67..0dccc475a53 100644
--- a/src/include/access/xlogdefs.h
+++ b/src/include/access/xlogdefs.h
@@ -41,7 +41,7 @@ pg_attribute_deprecated("use XLogRecPtrIsValid() instead")
 static inline bool
 XLogRecPtrIsInvalid(XLogRecPtr ptr)
 {
-	return ptr == InvalidXLogRecPtr;
+	return !XLogRecPtrIsValid(ptr);
 }
 
 /*
-- 
2.34.1

v6-0005-Replace-literal-0-comparisons-on-XLogRecPtr-with-.patchtext/x-diff; charset=us-asciiDownload
From d1c24d318b7ba4fc2558d92cc46d5a8d8f1f8fd7 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Wed, 29 Oct 2025 18:46:28 +0000
Subject: [PATCH v6 5/5] Replace literal 0 comparisons on XLogRecPtr with
 XLogRecPtrIsValid()

This commit ensures the XLogRecPtrIsValid() macro is used instead of direct
literal 0 comparisons on XLogRecPtr.
---
 src/backend/access/transam/xlogfuncs.c     | 4 ++--
 src/backend/replication/walreceiverfuncs.c | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)
  42.3% src/backend/access/transam/
  57.6% src/backend/replication/

diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index 8c3090165f0..3e45fce43ed 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -341,7 +341,7 @@ pg_last_wal_receive_lsn(PG_FUNCTION_ARGS)
 
 	recptr = GetWalRcvFlushRecPtr(NULL, NULL);
 
-	if (recptr == 0)
+	if (!XLogRecPtrIsValid(recptr))
 		PG_RETURN_NULL();
 
 	PG_RETURN_LSN(recptr);
@@ -360,7 +360,7 @@ pg_last_wal_replay_lsn(PG_FUNCTION_ARGS)
 
 	recptr = GetXLogReplayRecPtr(NULL);
 
-	if (recptr == 0)
+	if (!XLogRecPtrIsValid(recptr))
 		PG_RETURN_NULL();
 
 	PG_RETURN_LSN(recptr);
diff --git a/src/backend/replication/walreceiverfuncs.c b/src/backend/replication/walreceiverfuncs.c
index 6a693d854c4..822645748a7 100644
--- a/src/backend/replication/walreceiverfuncs.c
+++ b/src/backend/replication/walreceiverfuncs.c
@@ -315,7 +315,7 @@ RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, const char *conninfo,
 	 * If this is the first startup of walreceiver (on this timeline),
 	 * initialize flushedUpto and latestChunkStart to the starting point.
 	 */
-	if (walrcv->receiveStart == 0 || walrcv->receivedTLI != tli)
+	if (!XLogRecPtrIsValid(walrcv->receiveStart) || walrcv->receivedTLI != tli)
 	{
 		walrcv->flushedUpto = recptr;
 		walrcv->receivedTLI = tli;
-- 
2.34.1

#20Álvaro Herrera
alvherre@kurilemu.de
In reply to: Bertrand Drouvot (#19)
Re: Consistently use the XLogRecPtrIsInvalid() macro

On 2025-Nov-06, Bertrand Drouvot wrote:

I see, I would have introduced XLogRecPtrIsInvalid() on the back branches only
if there is a need to (a bugfix that would make use of it). But yeah, I agree
that would add extra "unnecessary" work, so done as you suggested in the
attached. I checked that 0001 apply on the [14-18]_STABLE branches successfully.

Okay, thanks, I have applied that one to all stable branches, except I
didn't add the judgemental comment about XLogRecPtrIsInvalid().

I also pushed 0002+0004+0005 together as one commit, so now we have
XLogRecPtrIsValid() everywhere.

I did a couple of minor transformations, where the new code would end
doing "!XLogRecPtrIsValid(x) ? A : B" it seems clearer to remove the
negation and invert the other two arguments in the ternary. We also had
this assertion,

- Assert(XLogRecPtrIsInvalid(state->istartpoint) == (state->istarttli == 0));

which was being transformed to have a negation. I chose to negate the
other side of the equality instead, that is,

+ Assert(XLogRecPtrIsValid(state->istartpoint) == (state->istarttli != 0));

which also seems clearer.

Now only 0003 remains ... I would change the complaining version to 21
there, because why not?

--
Álvaro Herrera 48°01'N 7°57'E — https://www.EnterpriseDB.com/
Maybe there's lots of data loss but the records of data loss are also lost.
(Lincoln Yeoh)

#21Bertrand Drouvot
bertranddrouvot.pg@gmail.com
In reply to: Álvaro Herrera (#20)
Re: Consistently use the XLogRecPtrIsInvalid() macro

Hi,

On Thu, Nov 06, 2025 at 08:48:11PM +0100, �lvaro Herrera wrote:

On 2025-Nov-06, Bertrand Drouvot wrote:

I see, I would have introduced XLogRecPtrIsInvalid() on the back branches only
if there is a need to (a bugfix that would make use of it). But yeah, I agree
that would add extra "unnecessary" work, so done as you suggested in the
attached. I checked that 0001 apply on the [14-18]_STABLE branches successfully.

Okay, thanks, I have applied that one to all stable branches, except I
didn't add the judgemental comment about XLogRecPtrIsInvalid().

I also pushed 0002+0004+0005 together as one commit, so now we have
XLogRecPtrIsValid() everywhere.

Thanks!

I did a couple of minor transformations, where the new code would end
doing "!XLogRecPtrIsValid(x) ? A : B" it seems clearer to remove the
negation and invert the other two arguments in the ternary. We also had
this assertion,

- Assert(XLogRecPtrIsInvalid(state->istartpoint) == (state->istarttli == 0));

which was being transformed to have a negation. I chose to negate the
other side of the equality instead, that is,

+ Assert(XLogRecPtrIsValid(state->istartpoint) == (state->istarttli != 0));

which also seems clearer.

Agree, will modify the .cocci scripts that way.

Now only 0003 remains ... I would change the complaining version to 21
there, because why not?

Now that XLogRecPtrIsValid() is available in back branches, I agree that we
can be less conservative and not wait until v24. v21 looks like good timing to
me.

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

#22Álvaro Herrera
alvherre@kurilemu.de
In reply to: Bertrand Drouvot (#21)
Re: Consistently use the XLogRecPtrIsInvalid() macro

On 2025-Nov-07, Bertrand Drouvot wrote:

Agree, will modify the .cocci scripts that way.

I just noticed that we missed this ... maybe you want to include it also?

diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index a0c79958fd5..1f11c8646f5 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -355,7 +355,7 @@ SyncRepWaitForLSN(XLogRecPtr lsn, bool commit)
 	pg_read_barrier();
 	Assert(dlist_node_is_detached(&MyProc->syncRepLinks));
 	MyProc->syncRepState = SYNC_REP_NOT_WAITING;
-	MyProc->waitLSN = 0;
+	MyProc->waitLSN = InvalidXLogRecPtr;

/* reset ps display to remove the suffix */
if (update_process_title)
@@ -1028,7 +1028,7 @@ SyncRepQueueIsOrderedByLSN(int mode)

Assert(mode >= 0 && mode < NUM_SYNC_REP_WAIT_MODE);

-	lastLSN = 0;
+	lastLSN = InvalidXLogRecPtr;
 	dlist_foreach(iter, &WalSndCtl->SyncRepQueue[mode])
 	{
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 1504fafe6d8..ce0d6a7539c 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -509,7 +509,7 @@ InitProcess(void)
 	MyProc->recoveryConflictPending = false;

/* Initialize fields for sync rep */
- MyProc->waitLSN = 0;
+ MyProc->waitLSN = InvalidXLogRecPtr;
MyProc->syncRepState = SYNC_REP_NOT_WAITING;
dlist_node_init(&MyProc->syncRepLinks);

Now that XLogRecPtrIsValid() is available in back branches, I agree that we
can be less conservative and not wait until v24. v21 looks like good timing to
me.

Cool, please resubmit.

--
Álvaro Herrera Breisgau, Deutschland — https://www.EnterpriseDB.com/
"They proved that being American is not just for some people"
(George Takei)

#23Bertrand Drouvot
bertranddrouvot.pg@gmail.com
In reply to: Álvaro Herrera (#22)
1 attachment(s)
Re: Consistently use the XLogRecPtrIsInvalid() macro

Hi,

On Fri, Nov 07, 2025 at 02:37:32PM +0100, �lvaro Herrera wrote:

On 2025-Nov-07, Bertrand Drouvot wrote:

Agree, will modify the .cocci scripts that way.

I just noticed that we missed this ... maybe you want to include it also?

-	MyProc->waitLSN = 0;
+	MyProc->waitLSN = InvalidXLogRecPtr;
-	lastLSN = 0;
+	lastLSN = InvalidXLogRecPtr;
-	MyProc->waitLSN = 0;
+	MyProc->waitLSN = InvalidXLogRecPtr;

Yeah, that's another story here that is worth to look at too. Will do.

I'm currently working on the RegProcedureIsValid() and OidIsValid() cases,
will share once done.

Now that XLogRecPtrIsValid() is available in back branches, I agree that we
can be less conservative and not wait until v24. v21 looks like good timing to
me.

Cool, please resubmit.

Sure, done in the attached.

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

Attachments:

v7-0001-Introduce-pg_attribute_deprecated-and-deprecate-X.patchtext/x-diff; charset=us-asciiDownload
From 98ea01f97cf0970898edd7795605f766b15a470f Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Fri, 7 Nov 2025 14:18:31 +0000
Subject: [PATCH v7] Introduce pg_attribute_deprecated() and deprecate
 XLogRecPtrIsInvalid()

This commit creates a new macro pg_attribute_deprecated() to mark a declaration
as deprecated with a custom message. The compiler will emit a warning when the
deprecated entity is used.

Then it makes use of this new macro to emit a deprecated message about
XLogRecPtrIsInvalid() as of version 21 (no need to be more conservative and wait
until version 24 as XLogRecPtrIsValid() has been added in back branches).
---
 src/include/access/xlogdefs.h | 17 +++++++++++++++++
 src/include/c.h               | 15 +++++++++++++++
 2 files changed, 32 insertions(+)
  47.2% src/include/access/
  52.7% src/include/

diff --git a/src/include/access/xlogdefs.h b/src/include/access/xlogdefs.h
index 5f07e57c832..1ed8f1b413e 100644
--- a/src/include/access/xlogdefs.h
+++ b/src/include/access/xlogdefs.h
@@ -27,6 +27,23 @@ typedef uint64 XLogRecPtr;
  */
 #define InvalidXLogRecPtr		0
 #define XLogRecPtrIsValid(r)	((r) != InvalidXLogRecPtr)
+
+/*
+ * New code should use XLogRecPtrIsValid() instead of XLogRecPtrIsInvalid()
+ * for consistency with the affirmative form of macros used for other datatypes
+ * and to avoid awkward double negative.
+ * This function is retained for convenience of third-party code but is/will be
+ * deprecated as of version 21.
+ */
+#if PG_VERSION_NUM >= 210000
+pg_attribute_deprecated("use XLogRecPtrIsValid() instead")
+#endif
+static inline bool
+XLogRecPtrIsInvalid(XLogRecPtr ptr)
+{
+	return ptr == InvalidXLogRecPtr;
+}
+
 #define XLogRecPtrIsInvalid(r)	((r) == InvalidXLogRecPtr)
 
 /*
diff --git a/src/include/c.h b/src/include/c.h
index 757dfff4782..6e7b2c47251 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -227,6 +227,21 @@
 #define PG_USED_FOR_ASSERTS_ONLY pg_attribute_unused()
 #endif
 
+/*
+ * Mark a declaration as deprecated with a custom message. The compiler will
+ * emit a warning when the deprecated entity is used.
+ */
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L || \
+defined(__cplusplus) && __cplusplus >= 201402L
+#define pg_attribute_deprecated(msg) [[deprecated(msg)]]
+#elif defined(__GNUC__) || defined(__clang__)
+#define pg_attribute_deprecated(msg) __attribute__((deprecated(msg)))
+#elif defined(_MSC_VER)
+#define pg_attribute_deprecated(msg) __declspec(deprecated(msg))
+#else
+#define pg_attribute_deprecated(msg)
+#endif
+
 /* GCC supports format attributes */
 #if defined(__GNUC__)
 #define pg_attribute_format_arg(a) __attribute__((format_arg(a)))
-- 
2.34.1

#24Peter Eisentraut
peter@eisentraut.org
In reply to: Bertrand Drouvot (#23)
Re: Consistently use the XLogRecPtrIsInvalid() macro

On 07.11.25 16:03, Bertrand Drouvot wrote:

+/*
+ * Mark a declaration as deprecated with a custom message. The compiler will
+ * emit a warning when the deprecated entity is used.
+ */
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L || \
+defined(__cplusplus) && __cplusplus >= 201402L

This could use some parentheses to disambiguate the && and ||.

Also the second line could be indented (or just put it on one line).

+#define pg_attribute_deprecated(msg) [[deprecated(msg)]]
+#elif defined(__GNUC__) || defined(__clang__)

The __clang__ part is not needed, because clang defines __GNUC__ also.

Show quoted text
+#define pg_attribute_deprecated(msg) __attribute__((deprecated(msg)))
+#elif defined(_MSC_VER)
+#define pg_attribute_deprecated(msg) __declspec(deprecated(msg))
+#else
+#define pg_attribute_deprecated(msg)
+#endif
#25Bertrand Drouvot
bertranddrouvot.pg@gmail.com
In reply to: Peter Eisentraut (#24)
1 attachment(s)
Re: Consistently use the XLogRecPtrIsInvalid() macro

Hi,

On Fri, Nov 07, 2025 at 05:05:11PM +0100, Peter Eisentraut wrote:

On 07.11.25 16:03, Bertrand Drouvot wrote:

+/*
+ * Mark a declaration as deprecated with a custom message. The compiler will
+ * emit a warning when the deprecated entity is used.
+ */
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L || \
+defined(__cplusplus) && __cplusplus >= 201402L

This could use some parentheses to disambiguate the && and ||.

Also the second line could be indented (or just put it on one line).

Agree that it could be more clear. Done that way in the attached (using only
one line as it looks more readable).

+#define pg_attribute_deprecated(msg) [[deprecated(msg)]]
+#elif defined(__GNUC__) || defined(__clang__)

The __clang__ part is not needed, because clang defines __GNUC__ also.

Good catch, thanks! Fixed in the attach.

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

Attachments:

v8-0001-Introduce-pg_attribute_deprecated-and-deprecate-X.patchtext/x-diff; charset=us-asciiDownload
From 5ce58b18992bbaf98eb4d0d0b9cf50e25a191aee Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Fri, 7 Nov 2025 14:18:31 +0000
Subject: [PATCH v8] Introduce pg_attribute_deprecated() and deprecate
 XLogRecPtrIsInvalid()

This commit creates a new macro pg_attribute_deprecated() to mark a declaration
as deprecated with a custom message. The compiler will emit a warning when the
deprecated entity is used.

Then it makes use of this new macro to emit a deprecated message about
XLogRecPtrIsInvalid() as of version 21 (no need to be more conservative and wait
until version 24 as XLogRecPtrIsValid() has been added in back branches).
---
 src/include/access/xlogdefs.h | 17 +++++++++++++++++
 src/include/c.h               | 14 ++++++++++++++
 2 files changed, 31 insertions(+)
  48.1% src/include/access/
  51.8% src/include/

diff --git a/src/include/access/xlogdefs.h b/src/include/access/xlogdefs.h
index 5f07e57c832..1ed8f1b413e 100644
--- a/src/include/access/xlogdefs.h
+++ b/src/include/access/xlogdefs.h
@@ -27,6 +27,23 @@ typedef uint64 XLogRecPtr;
  */
 #define InvalidXLogRecPtr		0
 #define XLogRecPtrIsValid(r)	((r) != InvalidXLogRecPtr)
+
+/*
+ * New code should use XLogRecPtrIsValid() instead of XLogRecPtrIsInvalid()
+ * for consistency with the affirmative form of macros used for other datatypes
+ * and to avoid awkward double negative.
+ * This function is retained for convenience of third-party code but is/will be
+ * deprecated as of version 21.
+ */
+#if PG_VERSION_NUM >= 210000
+pg_attribute_deprecated("use XLogRecPtrIsValid() instead")
+#endif
+static inline bool
+XLogRecPtrIsInvalid(XLogRecPtr ptr)
+{
+	return ptr == InvalidXLogRecPtr;
+}
+
 #define XLogRecPtrIsInvalid(r)	((r) == InvalidXLogRecPtr)
 
 /*
diff --git a/src/include/c.h b/src/include/c.h
index 757dfff4782..053635e984c 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -227,6 +227,20 @@
 #define PG_USED_FOR_ASSERTS_ONLY pg_attribute_unused()
 #endif
 
+/*
+ * Mark a declaration as deprecated with a custom message. The compiler will
+ * emit a warning when the deprecated entity is used.
+ */
+#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L) || (defined(__cplusplus) && __cplusplus >= 201402L)
+#define pg_attribute_deprecated(msg) [[deprecated(msg)]]
+#elif defined(__GNUC__)
+#define pg_attribute_deprecated(msg) __attribute__((deprecated(msg)))
+#elif defined(_MSC_VER)
+#define pg_attribute_deprecated(msg) __declspec(deprecated(msg))
+#else
+#define pg_attribute_deprecated(msg)
+#endif
+
 /* GCC supports format attributes */
 #if defined(__GNUC__)
 #define pg_attribute_format_arg(a) __attribute__((format_arg(a)))
-- 
2.34.1

In reply to: Peter Eisentraut (#24)
Re: Consistently use the XLogRecPtrIsInvalid() macro

Peter Eisentraut <peter@eisentraut.org> writes:

On 07.11.25 16:03, Bertrand Drouvot wrote:

+#define pg_attribute_deprecated(msg) [[deprecated(msg)]]
+#elif defined(__GNUC__) || defined(__clang__)

The __clang__ part is not needed, because clang defines __GNUC__ also.

Or, to avoid having to know this, how about __has_attribute(deprecated)?

- ilmari

#27Bertrand Drouvot
bertranddrouvot.pg@gmail.com
In reply to: Bertrand Drouvot (#23)
1 attachment(s)
Re: Consistently use the XLogRecPtrIsInvalid() macro

Hi,

On Fri, Nov 07, 2025 at 03:03:03PM +0000, Bertrand Drouvot wrote:

Hi,

On Fri, Nov 07, 2025 at 02:37:32PM +0100, �lvaro Herrera wrote:

On 2025-Nov-07, Bertrand Drouvot wrote:

Agree, will modify the .cocci scripts that way.

I just noticed that we missed this ... maybe you want to include it also?

-	MyProc->waitLSN = 0;
+	MyProc->waitLSN = InvalidXLogRecPtr;
-	lastLSN = 0;
+	lastLSN = InvalidXLogRecPtr;
-	MyProc->waitLSN = 0;
+	MyProc->waitLSN = InvalidXLogRecPtr;

Yeah, that's another story here that is worth to look at too. Will do.

What do you think of the attached? It contains the ones you mentioned and some
others. The patch attached has been generated by the .cocci script [1]https://github.com/bdrouvot/coccinelle_on_pg/blob/main/replace_literal_0_assignement_with_InvalidXLogRecPtr.cocci.

[1]: https://github.com/bdrouvot/coccinelle_on_pg/blob/main/replace_literal_0_assignement_with_InvalidXLogRecPtr.cocci

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

Attachments:

v8-0001-Replace-literal-0-with-InvalidXLogRecPtr-for-XLog.patchtext/x-diff; charset=us-asciiDownload
From d26727aa093aaba126345a134c64399c66b2a8c0 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Fri, 7 Nov 2025 16:47:38 +0000
Subject: [PATCH v8] Replace literal 0 with InvalidXLogRecPtr for XLogRecPtr
 assignments

Use the proper constant InvalidXLogRecPtr instead of literal 0 when
assigning XLogRecPtr variables and struct fields.

This improves code clarity by making it explicit that these are
invalid LSN values rather than ambiguous zero literals.
---
 src/backend/access/transam/parallel.c       | 4 ++--
 src/backend/access/transam/xlog.c           | 6 +++---
 src/backend/access/transam/xlogprefetcher.c | 2 +-
 src/backend/access/transam/xlogrecovery.c   | 6 +++---
 src/backend/replication/syncrep.c           | 4 ++--
 src/backend/replication/walreceiver.c       | 4 ++--
 src/backend/storage/lmgr/proc.c             | 2 +-
 src/bin/pg_resetwal/pg_resetwal.c           | 8 ++++----
 src/bin/pg_rewind/pg_rewind.c               | 2 +-
 9 files changed, 19 insertions(+), 19 deletions(-)
  47.9% src/backend/access/transam/
  19.7% src/backend/replication/
   4.4% src/backend/storage/lmgr/
  23.0% src/bin/pg_resetwal/
   4.8% src/bin/pg_rewind/

diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index 94db1ec3012..14ef12a4dd5 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -356,7 +356,7 @@ InitializeParallelDSM(ParallelContext *pcxt)
 	fps->stmt_ts = GetCurrentStatementStartTimestamp();
 	fps->serializable_xact_handle = ShareSerializableXact();
 	SpinLockInit(&fps->mutex);
-	fps->last_xlog_end = 0;
+	fps->last_xlog_end = InvalidXLogRecPtr;
 	shm_toc_insert(pcxt->toc, PARALLEL_KEY_FIXED, fps);
 
 	/* We can skip the rest of this if we're not budgeting for any workers. */
@@ -525,7 +525,7 @@ ReinitializeParallelDSM(ParallelContext *pcxt)
 
 	/* Reset a few bits of fixed parallel state to a clean state. */
 	fps = shm_toc_lookup(pcxt->toc, PARALLEL_KEY_FIXED, false);
-	fps->last_xlog_end = 0;
+	fps->last_xlog_end = InvalidXLogRecPtr;
 
 	/* Recreate error queues (if they exist). */
 	if (pcxt->nworkers > 0)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 101b616b028..1d6a75dc995 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -2060,7 +2060,7 @@ AdvanceXLInsertBuffer(XLogRecPtr upto, TimeLineID tli, bool opportunistic)
 					/* Have to write it ourselves */
 					TRACE_POSTGRESQL_WAL_BUFFER_WRITE_DIRTY_START();
 					WriteRqst.Write = OldPageRqstPtr;
-					WriteRqst.Flush = 0;
+					WriteRqst.Flush = InvalidXLogRecPtr;
 					XLogWrite(WriteRqst, tli, false);
 					LWLockRelease(WALWriteLock);
 					pgWalUsage.wal_buffers_full++;
@@ -3067,7 +3067,7 @@ XLogBackgroundFlush(void)
 	else
 	{
 		/* no flushing, this time round */
-		WriteRqst.Flush = 0;
+		WriteRqst.Flush = InvalidXLogRecPtr;
 	}
 
 #ifdef WAL_DEBUG
@@ -5160,7 +5160,7 @@ BootStrapXLOG(uint32 data_checksum_version)
 	/* Insert the initial checkpoint record */
 	recptr = ((char *) page + SizeOfXLogLongPHD);
 	record = (XLogRecord *) recptr;
-	record->xl_prev = 0;
+	record->xl_prev = InvalidXLogRecPtr;
 	record->xl_xid = InvalidTransactionId;
 	record->xl_tot_len = SizeOfXLogRecord + SizeOfXLogRecordDataHeaderShort + sizeof(checkPoint);
 	record->xl_info = XLOG_CHECKPOINT_SHUTDOWN;
diff --git a/src/backend/access/transam/xlogprefetcher.c b/src/backend/access/transam/xlogprefetcher.c
index ed3aacabc98..a1ef603f5f9 100644
--- a/src/backend/access/transam/xlogprefetcher.c
+++ b/src/backend/access/transam/xlogprefetcher.c
@@ -967,7 +967,7 @@ XLogPrefetcherBeginRead(XLogPrefetcher *prefetcher, XLogRecPtr recPtr)
 	/* Book-keeping to avoid readahead on first read. */
 	prefetcher->begin_ptr = recPtr;
 
-	prefetcher->no_readahead_until = 0;
+	prefetcher->no_readahead_until = InvalidXLogRecPtr;
 
 	/* This will forget about any queued up records in the decoder. */
 	XLogBeginRead(prefetcher->reader, recPtr);
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index eddc22fc5ad..3acb04f98fd 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -262,7 +262,7 @@ static TimestampTz XLogReceiptTime = 0;
 static XLogSource XLogReceiptSource = XLOG_FROM_ANY;
 
 /* Local copy of WalRcv->flushedUpto */
-static XLogRecPtr flushedUpto = 0;
+static XLogRecPtr flushedUpto = InvalidXLogRecPtr;
 static TimeLineID receiveTLI = 0;
 
 /*
@@ -3909,7 +3909,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 						RequestXLogStreaming(tli, ptr, PrimaryConnInfo,
 											 PrimarySlotName,
 											 wal_receiver_create_temp_slot);
-						flushedUpto = 0;
+						flushedUpto = InvalidXLogRecPtr;
 					}
 
 					/*
@@ -4087,7 +4087,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 static int
 emode_for_corrupt_record(int emode, XLogRecPtr RecPtr)
 {
-	static XLogRecPtr lastComplaint = 0;
+	static XLogRecPtr lastComplaint = InvalidXLogRecPtr;
 
 	if (readSource == XLOG_FROM_PG_WAL && emode == LOG)
 	{
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index a0c79958fd5..1f11c8646f5 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -355,7 +355,7 @@ SyncRepWaitForLSN(XLogRecPtr lsn, bool commit)
 	pg_read_barrier();
 	Assert(dlist_node_is_detached(&MyProc->syncRepLinks));
 	MyProc->syncRepState = SYNC_REP_NOT_WAITING;
-	MyProc->waitLSN = 0;
+	MyProc->waitLSN = InvalidXLogRecPtr;
 
 	/* reset ps display to remove the suffix */
 	if (update_process_title)
@@ -1028,7 +1028,7 @@ SyncRepQueueIsOrderedByLSN(int mode)
 
 	Assert(mode >= 0 && mode < NUM_SYNC_REP_WAIT_MODE);
 
-	lastLSN = 0;
+	lastLSN = InvalidXLogRecPtr;
 
 	dlist_foreach(iter, &WalSndCtl->SyncRepQueue[mode])
 	{
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index 2ee8fecee26..f38a599f1cf 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1091,8 +1091,8 @@ XLogWalRcvClose(XLogRecPtr recptr, TimeLineID tli)
 static void
 XLogWalRcvSendReply(bool force, bool requestReply)
 {
-	static XLogRecPtr writePtr = 0;
-	static XLogRecPtr flushPtr = 0;
+	static XLogRecPtr writePtr = InvalidXLogRecPtr;
+	static XLogRecPtr flushPtr = InvalidXLogRecPtr;
 	XLogRecPtr	applyPtr;
 	TimestampTz now;
 
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 1504fafe6d8..ce0d6a7539c 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -509,7 +509,7 @@ InitProcess(void)
 	MyProc->recoveryConflictPending = false;
 
 	/* Initialize fields for sync rep */
-	MyProc->waitLSN = 0;
+	MyProc->waitLSN = InvalidXLogRecPtr;
 	MyProc->syncRepState = SYNC_REP_NOT_WAITING;
 	dlist_node_init(&MyProc->syncRepLinks);
 
diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c
index a89d72fc5cf..73d508dee2d 100644
--- a/src/bin/pg_resetwal/pg_resetwal.c
+++ b/src/bin/pg_resetwal/pg_resetwal.c
@@ -878,10 +878,10 @@ RewriteControlFile(void)
 
 	ControlFile.state = DB_SHUTDOWNED;
 	ControlFile.checkPoint = ControlFile.checkPointCopy.redo;
-	ControlFile.minRecoveryPoint = 0;
+	ControlFile.minRecoveryPoint = InvalidXLogRecPtr;
 	ControlFile.minRecoveryPointTLI = 0;
-	ControlFile.backupStartPoint = 0;
-	ControlFile.backupEndPoint = 0;
+	ControlFile.backupStartPoint = InvalidXLogRecPtr;
+	ControlFile.backupEndPoint = InvalidXLogRecPtr;
 	ControlFile.backupEndRequired = false;
 
 	/*
@@ -1112,7 +1112,7 @@ WriteEmptyXLOG(void)
 	/* Insert the initial checkpoint record */
 	recptr = (char *) page + SizeOfXLogLongPHD;
 	record = (XLogRecord *) recptr;
-	record->xl_prev = 0;
+	record->xl_prev = InvalidXLogRecPtr;
 	record->xl_xid = InvalidTransactionId;
 	record->xl_tot_len = SizeOfXLogRecord + SizeOfXLogRecordDataHeaderShort + sizeof(CheckPoint);
 	record->xl_info = XLOG_CHECKPOINT_SHUTDOWN;
diff --git a/src/bin/pg_rewind/pg_rewind.c b/src/bin/pg_rewind/pg_rewind.c
index 27c514f934a..f92fe37bc20 100644
--- a/src/bin/pg_rewind/pg_rewind.c
+++ b/src/bin/pg_rewind/pg_rewind.c
@@ -375,7 +375,7 @@ main(int argc, char **argv)
 	{
 		pg_log_info("source and target cluster are on the same timeline");
 		rewind_needed = false;
-		target_wal_endrec = 0;
+		target_wal_endrec = InvalidXLogRecPtr;
 	}
 	else
 	{
-- 
2.34.1

#28Bertrand Drouvot
bertranddrouvot.pg@gmail.com
In reply to: Dagfinn Ilmari Mannsåker (#26)
1 attachment(s)
Re: Consistently use the XLogRecPtrIsInvalid() macro

Hi,

On Fri, Nov 07, 2025 at 05:18:41PM +0000, Dagfinn Ilmari Manns�ker wrote:

Peter Eisentraut <peter@eisentraut.org> writes:

On 07.11.25 16:03, Bertrand Drouvot wrote:

+#define pg_attribute_deprecated(msg) [[deprecated(msg)]]
+#elif defined(__GNUC__) || defined(__clang__)

The __clang__ part is not needed, because clang defines __GNUC__ also.

Or, to avoid having to know this, how about __has_attribute(deprecated)?

Thanks for looking at it! I did some research and found that some older GCC
versions did support the deprecated attribute (for example GCC 4.5 added support
to the extra message, see [1]https://gcc.gnu.org/gcc-4.5/changes.html) but not __has_attribute (introduced in GCC 5, see
[2]: https://gcc.gnu.org/gcc-5/changes.html

Then to be on the safe side of things I think it's better to not use
__has_attribute() for the deprecated attribute.

I added a comment in the attached though.

[1]: https://gcc.gnu.org/gcc-4.5/changes.html
[2]: https://gcc.gnu.org/gcc-5/changes.html

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

Attachments:

v9-0001-Introduce-pg_attribute_deprecated-and-deprecate-X.patchtext/x-diff; charset=us-asciiDownload
From 750e128f9c6867e37c33051fc00aa672568153f8 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Fri, 7 Nov 2025 14:18:31 +0000
Subject: [PATCH v9] Introduce pg_attribute_deprecated() and deprecate
 XLogRecPtrIsInvalid()

This commit creates a new macro pg_attribute_deprecated() to mark a declaration
as deprecated with a custom message. The compiler will emit a warning when the
deprecated entity is used.

Then it makes use of this new macro to emit a deprecated message about
XLogRecPtrIsInvalid() as of version 21 (no need to be more conservative and wait
until version 24 as XLogRecPtrIsValid() has been added in back branches).
---
 src/include/access/xlogdefs.h | 17 ++++++++++++++++-
 src/include/c.h               | 16 ++++++++++++++++
 2 files changed, 32 insertions(+), 1 deletion(-)
  44.7% src/include/access/
  55.2% src/include/

diff --git a/src/include/access/xlogdefs.h b/src/include/access/xlogdefs.h
index 5f07e57c832..1ab33ad59c8 100644
--- a/src/include/access/xlogdefs.h
+++ b/src/include/access/xlogdefs.h
@@ -27,7 +27,22 @@ typedef uint64 XLogRecPtr;
  */
 #define InvalidXLogRecPtr		0
 #define XLogRecPtrIsValid(r)	((r) != InvalidXLogRecPtr)
-#define XLogRecPtrIsInvalid(r)	((r) == InvalidXLogRecPtr)
+
+/*
+ * New code should use XLogRecPtrIsValid() instead of XLogRecPtrIsInvalid()
+ * for consistency with the affirmative form of macros used for other datatypes
+ * and to avoid awkward double negative.
+ * This function is retained for convenience of third-party code but is/will be
+ * deprecated as of version 21.
+ */
+#if PG_VERSION_NUM >= 210000
+pg_attribute_deprecated("use XLogRecPtrIsValid() instead")
+#endif
+static inline bool
+XLogRecPtrIsInvalid(XLogRecPtr ptr)
+{
+	return ptr == InvalidXLogRecPtr;
+}
 
 /*
  * First LSN to use for "fake" LSNs.
diff --git a/src/include/c.h b/src/include/c.h
index 757dfff4782..22600cbe3a0 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -227,6 +227,22 @@
 #define PG_USED_FOR_ASSERTS_ONLY pg_attribute_unused()
 #endif
 
+/*
+ * Mark a declaration as deprecated with a custom message. The compiler will
+ * emit a warning when the deprecated entity is used.
+ * Note: Some older compilers support the attribute but not __has_attribute,
+ * which may cause this check to fail. Using compiler detection instead.
+ */
+#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L) || (defined(__cplusplus) && __cplusplus >= 201402L)
+#define pg_attribute_deprecated(msg) [[deprecated(msg)]]
+#elif defined(__GNUC__)
+#define pg_attribute_deprecated(msg) __attribute__((deprecated(msg)))
+#elif defined(_MSC_VER)
+#define pg_attribute_deprecated(msg) __declspec(deprecated(msg))
+#else
+#define pg_attribute_deprecated(msg)
+#endif
+
 /* GCC supports format attributes */
 #if defined(__GNUC__)
 #define pg_attribute_format_arg(a) __attribute__((format_arg(a)))
-- 
2.34.1

#29Álvaro Herrera
alvherre@kurilemu.de
In reply to: Bertrand Drouvot (#27)
2 attachment(s)
Re: Consistently use the XLogRecPtrIsInvalid() macro

On 2025-Nov-07, Bertrand Drouvot wrote:

What do you think of the attached? It contains the ones you mentioned and some
others. The patch attached has been generated by the .cocci script [1].

[1]: https://github.com/bdrouvot/coccinelle_on_pg/blob/main/replace_literal_0_assignement_with_InvalidXLogRecPtr.cocci

Hmm, I tried to recreate your patch using this .cocci file, and in my
run, there's a few changes in your patch that my spatch run didn't
detect. I wonder if that's because my spatch version is buggy, or
because you hacked the .cocci file beyond what's in your github repo.

In case you're curious, here's two commits: what I got with my spatch
run as a first step, and then the patch you sent on top of that.

(I'm wondering if I should reproduce your previous patches in case there
were also differences there. Life is short though.)

--
Álvaro Herrera Breisgau, Deutschland — https://www.EnterpriseDB.com/

Attachments:

v9-0001-my-spatch-run.patchtext/x-diff; charset=utf-8Download
From 449e1327a49403bc054dfd224e2453ef398c2b0d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C3=81lvaro=20Herrera?= <alvherre@kurilemu.de>
Date: Thu, 13 Nov 2025 13:45:16 +0100
Subject: [PATCH v9 1/2] my spatch run

---
 src/backend/access/transam/parallel.c       | 4 ++--
 src/backend/access/transam/xlog.c           | 2 +-
 src/backend/access/transam/xlogprefetcher.c | 2 +-
 src/backend/access/transam/xlogrecovery.c   | 6 +++---
 src/backend/replication/syncrep.c           | 2 +-
 src/backend/replication/walreceiver.c       | 4 ++--
 src/bin/pg_rewind/pg_rewind.c               | 2 +-
 7 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index 94db1ec3012..14ef12a4dd5 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -356,7 +356,7 @@ InitializeParallelDSM(ParallelContext *pcxt)
 	fps->stmt_ts = GetCurrentStatementStartTimestamp();
 	fps->serializable_xact_handle = ShareSerializableXact();
 	SpinLockInit(&fps->mutex);
-	fps->last_xlog_end = 0;
+	fps->last_xlog_end = InvalidXLogRecPtr;
 	shm_toc_insert(pcxt->toc, PARALLEL_KEY_FIXED, fps);
 
 	/* We can skip the rest of this if we're not budgeting for any workers. */
@@ -525,7 +525,7 @@ ReinitializeParallelDSM(ParallelContext *pcxt)
 
 	/* Reset a few bits of fixed parallel state to a clean state. */
 	fps = shm_toc_lookup(pcxt->toc, PARALLEL_KEY_FIXED, false);
-	fps->last_xlog_end = 0;
+	fps->last_xlog_end = InvalidXLogRecPtr;
 
 	/* Recreate error queues (if they exist). */
 	if (pcxt->nworkers > 0)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 22d0a2e8c3a..0838020fa33 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -3067,7 +3067,7 @@ XLogBackgroundFlush(void)
 	else
 	{
 		/* no flushing, this time round */
-		WriteRqst.Flush = 0;
+		WriteRqst.Flush = InvalidXLogRecPtr;
 	}
 
 #ifdef WAL_DEBUG
diff --git a/src/backend/access/transam/xlogprefetcher.c b/src/backend/access/transam/xlogprefetcher.c
index ed3aacabc98..a1ef603f5f9 100644
--- a/src/backend/access/transam/xlogprefetcher.c
+++ b/src/backend/access/transam/xlogprefetcher.c
@@ -967,7 +967,7 @@ XLogPrefetcherBeginRead(XLogPrefetcher *prefetcher, XLogRecPtr recPtr)
 	/* Book-keeping to avoid readahead on first read. */
 	prefetcher->begin_ptr = recPtr;
 
-	prefetcher->no_readahead_until = 0;
+	prefetcher->no_readahead_until = InvalidXLogRecPtr;
 
 	/* This will forget about any queued up records in the decoder. */
 	XLogBeginRead(prefetcher->reader, recPtr);
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index eddc22fc5ad..3acb04f98fd 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -262,7 +262,7 @@ static TimestampTz XLogReceiptTime = 0;
 static XLogSource XLogReceiptSource = XLOG_FROM_ANY;
 
 /* Local copy of WalRcv->flushedUpto */
-static XLogRecPtr flushedUpto = 0;
+static XLogRecPtr flushedUpto = InvalidXLogRecPtr;
 static TimeLineID receiveTLI = 0;
 
 /*
@@ -3909,7 +3909,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 						RequestXLogStreaming(tli, ptr, PrimaryConnInfo,
 											 PrimarySlotName,
 											 wal_receiver_create_temp_slot);
-						flushedUpto = 0;
+						flushedUpto = InvalidXLogRecPtr;
 					}
 
 					/*
@@ -4087,7 +4087,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 static int
 emode_for_corrupt_record(int emode, XLogRecPtr RecPtr)
 {
-	static XLogRecPtr lastComplaint = 0;
+	static XLogRecPtr lastComplaint = InvalidXLogRecPtr;
 
 	if (readSource == XLOG_FROM_PG_WAL && emode == LOG)
 	{
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index a0c79958fd5..89c513d4346 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -1028,7 +1028,7 @@ SyncRepQueueIsOrderedByLSN(int mode)
 
 	Assert(mode >= 0 && mode < NUM_SYNC_REP_WAIT_MODE);
 
-	lastLSN = 0;
+	lastLSN = InvalidXLogRecPtr;
 
 	dlist_foreach(iter, &WalSndCtl->SyncRepQueue[mode])
 	{
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index 2ee8fecee26..f38a599f1cf 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1091,8 +1091,8 @@ XLogWalRcvClose(XLogRecPtr recptr, TimeLineID tli)
 static void
 XLogWalRcvSendReply(bool force, bool requestReply)
 {
-	static XLogRecPtr writePtr = 0;
-	static XLogRecPtr flushPtr = 0;
+	static XLogRecPtr writePtr = InvalidXLogRecPtr;
+	static XLogRecPtr flushPtr = InvalidXLogRecPtr;
 	XLogRecPtr	applyPtr;
 	TimestampTz now;
 
diff --git a/src/bin/pg_rewind/pg_rewind.c b/src/bin/pg_rewind/pg_rewind.c
index 27c514f934a..f92fe37bc20 100644
--- a/src/bin/pg_rewind/pg_rewind.c
+++ b/src/bin/pg_rewind/pg_rewind.c
@@ -375,7 +375,7 @@ main(int argc, char **argv)
 	{
 		pg_log_info("source and target cluster are on the same timeline");
 		rewind_needed = false;
-		target_wal_endrec = 0;
+		target_wal_endrec = InvalidXLogRecPtr;
 	}
 	else
 	{
-- 
2.47.3

v9-0002-Replace-literal-0-with-InvalidXLogRecPtr-for-XLog.patchtext/x-diff; charset=utf-8Download
From d1b0d407f589deaea90b400eea97806f10d99cc6 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Fri, 7 Nov 2025 16:47:38 +0000
Subject: [PATCH v9 2/2] Replace literal 0 with InvalidXLogRecPtr for
 XLogRecPtr assignments

Use the proper constant InvalidXLogRecPtr instead of literal 0 when
assigning XLogRecPtr variables and struct fields.

This improves code clarity by making it explicit that these are
invalid LSN values rather than ambiguous zero literals.
---
 src/backend/access/transam/xlog.c | 4 ++--
 src/backend/replication/syncrep.c | 2 +-
 src/backend/storage/lmgr/proc.c   | 2 +-
 src/bin/pg_resetwal/pg_resetwal.c | 8 ++++----
 4 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 0838020fa33..f5cb9313f11 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -2060,7 +2060,7 @@ AdvanceXLInsertBuffer(XLogRecPtr upto, TimeLineID tli, bool opportunistic)
 					/* Have to write it ourselves */
 					TRACE_POSTGRESQL_WAL_BUFFER_WRITE_DIRTY_START();
 					WriteRqst.Write = OldPageRqstPtr;
-					WriteRqst.Flush = 0;
+					WriteRqst.Flush = InvalidXLogRecPtr;
 					XLogWrite(WriteRqst, tli, false);
 					LWLockRelease(WALWriteLock);
 					pgWalUsage.wal_buffers_full++;
@@ -5171,7 +5171,7 @@ BootStrapXLOG(uint32 data_checksum_version)
 	/* Insert the initial checkpoint record */
 	recptr = ((char *) page + SizeOfXLogLongPHD);
 	record = (XLogRecord *) recptr;
-	record->xl_prev = 0;
+	record->xl_prev = InvalidXLogRecPtr;
 	record->xl_xid = InvalidTransactionId;
 	record->xl_tot_len = SizeOfXLogRecord + SizeOfXLogRecordDataHeaderShort + sizeof(checkPoint);
 	record->xl_info = XLOG_CHECKPOINT_SHUTDOWN;
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index 89c513d4346..1f11c8646f5 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -355,7 +355,7 @@ SyncRepWaitForLSN(XLogRecPtr lsn, bool commit)
 	pg_read_barrier();
 	Assert(dlist_node_is_detached(&MyProc->syncRepLinks));
 	MyProc->syncRepState = SYNC_REP_NOT_WAITING;
-	MyProc->waitLSN = 0;
+	MyProc->waitLSN = InvalidXLogRecPtr;
 
 	/* reset ps display to remove the suffix */
 	if (update_process_title)
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 1504fafe6d8..ce0d6a7539c 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -509,7 +509,7 @@ InitProcess(void)
 	MyProc->recoveryConflictPending = false;
 
 	/* Initialize fields for sync rep */
-	MyProc->waitLSN = 0;
+	MyProc->waitLSN = InvalidXLogRecPtr;
 	MyProc->syncRepState = SYNC_REP_NOT_WAITING;
 	dlist_node_init(&MyProc->syncRepLinks);
 
diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c
index a31e7643cf0..2c938011144 100644
--- a/src/bin/pg_resetwal/pg_resetwal.c
+++ b/src/bin/pg_resetwal/pg_resetwal.c
@@ -886,10 +886,10 @@ RewriteControlFile(void)
 
 	ControlFile.state = DB_SHUTDOWNED;
 	ControlFile.checkPoint = ControlFile.checkPointCopy.redo;
-	ControlFile.minRecoveryPoint = 0;
+	ControlFile.minRecoveryPoint = InvalidXLogRecPtr;
 	ControlFile.minRecoveryPointTLI = 0;
-	ControlFile.backupStartPoint = 0;
-	ControlFile.backupEndPoint = 0;
+	ControlFile.backupStartPoint = InvalidXLogRecPtr;
+	ControlFile.backupEndPoint = InvalidXLogRecPtr;
 	ControlFile.backupEndRequired = false;
 
 	/*
@@ -1120,7 +1120,7 @@ WriteEmptyXLOG(void)
 	/* Insert the initial checkpoint record */
 	recptr = (char *) page + SizeOfXLogLongPHD;
 	record = (XLogRecord *) recptr;
-	record->xl_prev = 0;
+	record->xl_prev = InvalidXLogRecPtr;
 	record->xl_xid = InvalidTransactionId;
 	record->xl_tot_len = SizeOfXLogRecord + SizeOfXLogRecordDataHeaderShort + sizeof(CheckPoint);
 	record->xl_info = XLOG_CHECKPOINT_SHUTDOWN;
-- 
2.47.3

#30Bertrand Drouvot
bertranddrouvot.pg@gmail.com
In reply to: Álvaro Herrera (#29)
Re: Consistently use the XLogRecPtrIsInvalid() macro

On Fri, Nov 07, 2025 at 02:37:32PM +0100, �lvaro Herrera wrote:

Hmm, I tried to recreate your patch using this .cocci file, and in my
run, there's a few changes in your patch that my spatch run didn't
detect. I wonder if that's because my spatch version is buggy, or
because you hacked the .cocci file beyond what's in your github repo.

spatch needs to be run with --recursive-includes (so that the .cocci script
is able to collect information from all the structs of interest). The header
comment in the .cocci script did not mention that: just fixed).

But then I realized that if I run spatch that way:

spatch --sp-file replace_literal_0_assignement_with_InvalidXLogRecPtr.cocci \
--dir /path/to/postgres/src \
-I /path/to/postgres/src/include \
--recursive-includes \

replace.patch

Then some headers were not included (no clue as to why). But if I run spatch on
the .c files one by one with the --recursive-includes then it works (i.e all
the headers of interest are included).

So, I created [1]https://github.com/bdrouvot/coccinelle_on_pg/blob/main/wrappers/run_parallel.sh to run spatch one by one on all the .c files (in parallel).

To produce the patch that I shared I ran:

./run_parallel.sh /absolute_path_to/replace_literal_0_assignement_with_InvalidXLogRecPtr.cocci -j 32

(patch can be found in /path/to/postgres once completed).

(I'm wondering if I should reproduce your previous patches in case there
were also differences there. Life is short though.)

I guess/hope you'll get the same results if you use run_parallel.sh as mentioned
above.

[1]: https://github.com/bdrouvot/coccinelle_on_pg/blob/main/wrappers/run_parallel.sh

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

#31Bertrand Drouvot
bertranddrouvot.pg@gmail.com
In reply to: Bertrand Drouvot (#30)
1 attachment(s)
Re: Consistently use the XLogRecPtrIsInvalid() macro

Hi,

On Thu, Nov 13, 2025 at 02:11:08PM +0000, Bertrand Drouvot wrote:

On Fri, Nov 07, 2025 at 02:37:32PM +0100, �lvaro Herrera wrote:

I guess/hope you'll get the same results if you use run_parallel.sh as mentioned
above.

The .cocci script had an issue (not always detecting correctly direct member
access).

The script has been updated and the patch too (finding a new replacement in
gist.c).

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

Attachments:

v9-0001-Replace-literal-0-with-InvalidXLogRecPtr-for-XLog.patchtext/x-diff; charset=us-asciiDownload
From 9ea74aa1db40296295fb44965347c36a19b59263 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Mon, 17 Nov 2025 12:28:51 +0000
Subject: [PATCH v9] Replace literal 0 with InvalidXLogRecPtr for XLogRecPtr
 assignments

Use the proper constant InvalidXLogRecPtr instead of literal 0 when
assigning XLogRecPtr variables and struct fields.

This improves code clarity by making it explicit that these are
invalid LSN values rather than ambiguous zero literals.
---
 src/backend/access/gist/gist.c              | 2 +-
 src/backend/access/transam/parallel.c       | 4 ++--
 src/backend/access/transam/xlog.c           | 6 +++---
 src/backend/access/transam/xlogprefetcher.c | 2 +-
 src/backend/access/transam/xlogrecovery.c   | 6 +++---
 src/backend/replication/syncrep.c           | 4 ++--
 src/backend/replication/walreceiver.c       | 4 ++--
 src/backend/storage/lmgr/proc.c             | 2 +-
 src/bin/pg_resetwal/pg_resetwal.c           | 8 ++++----
 src/bin/pg_rewind/pg_rewind.c               | 2 +-
 10 files changed, 20 insertions(+), 20 deletions(-)
   4.0% src/backend/access/gist/
  45.9% src/backend/access/transam/
  18.8% src/backend/replication/
   4.2% src/backend/storage/lmgr/
  22.1% src/bin/pg_resetwal/
   4.6% src/bin/pg_rewind/

diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c
index 3fb1a1285c5..190d7ae0c18 100644
--- a/src/backend/access/gist/gist.c
+++ b/src/backend/access/gist/gist.c
@@ -653,7 +653,7 @@ gistdoinsert(Relation r, IndexTuple itup, Size freespace,
 
 	/* Start from the root */
 	firststack.blkno = GIST_ROOT_BLKNO;
-	firststack.lsn = 0;
+	firststack.lsn = InvalidXLogRecPtr;
 	firststack.retry_from_parent = false;
 	firststack.parent = NULL;
 	firststack.downlinkoffnum = InvalidOffsetNumber;
diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index 94db1ec3012..14ef12a4dd5 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -356,7 +356,7 @@ InitializeParallelDSM(ParallelContext *pcxt)
 	fps->stmt_ts = GetCurrentStatementStartTimestamp();
 	fps->serializable_xact_handle = ShareSerializableXact();
 	SpinLockInit(&fps->mutex);
-	fps->last_xlog_end = 0;
+	fps->last_xlog_end = InvalidXLogRecPtr;
 	shm_toc_insert(pcxt->toc, PARALLEL_KEY_FIXED, fps);
 
 	/* We can skip the rest of this if we're not budgeting for any workers. */
@@ -525,7 +525,7 @@ ReinitializeParallelDSM(ParallelContext *pcxt)
 
 	/* Reset a few bits of fixed parallel state to a clean state. */
 	fps = shm_toc_lookup(pcxt->toc, PARALLEL_KEY_FIXED, false);
-	fps->last_xlog_end = 0;
+	fps->last_xlog_end = InvalidXLogRecPtr;
 
 	/* Recreate error queues (if they exist). */
 	if (pcxt->nworkers > 0)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 22d0a2e8c3a..f5cb9313f11 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -2060,7 +2060,7 @@ AdvanceXLInsertBuffer(XLogRecPtr upto, TimeLineID tli, bool opportunistic)
 					/* Have to write it ourselves */
 					TRACE_POSTGRESQL_WAL_BUFFER_WRITE_DIRTY_START();
 					WriteRqst.Write = OldPageRqstPtr;
-					WriteRqst.Flush = 0;
+					WriteRqst.Flush = InvalidXLogRecPtr;
 					XLogWrite(WriteRqst, tli, false);
 					LWLockRelease(WALWriteLock);
 					pgWalUsage.wal_buffers_full++;
@@ -3067,7 +3067,7 @@ XLogBackgroundFlush(void)
 	else
 	{
 		/* no flushing, this time round */
-		WriteRqst.Flush = 0;
+		WriteRqst.Flush = InvalidXLogRecPtr;
 	}
 
 #ifdef WAL_DEBUG
@@ -5171,7 +5171,7 @@ BootStrapXLOG(uint32 data_checksum_version)
 	/* Insert the initial checkpoint record */
 	recptr = ((char *) page + SizeOfXLogLongPHD);
 	record = (XLogRecord *) recptr;
-	record->xl_prev = 0;
+	record->xl_prev = InvalidXLogRecPtr;
 	record->xl_xid = InvalidTransactionId;
 	record->xl_tot_len = SizeOfXLogRecord + SizeOfXLogRecordDataHeaderShort + sizeof(checkPoint);
 	record->xl_info = XLOG_CHECKPOINT_SHUTDOWN;
diff --git a/src/backend/access/transam/xlogprefetcher.c b/src/backend/access/transam/xlogprefetcher.c
index ed3aacabc98..a1ef603f5f9 100644
--- a/src/backend/access/transam/xlogprefetcher.c
+++ b/src/backend/access/transam/xlogprefetcher.c
@@ -967,7 +967,7 @@ XLogPrefetcherBeginRead(XLogPrefetcher *prefetcher, XLogRecPtr recPtr)
 	/* Book-keeping to avoid readahead on first read. */
 	prefetcher->begin_ptr = recPtr;
 
-	prefetcher->no_readahead_until = 0;
+	prefetcher->no_readahead_until = InvalidXLogRecPtr;
 
 	/* This will forget about any queued up records in the decoder. */
 	XLogBeginRead(prefetcher->reader, recPtr);
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index 21b8f179ba0..3237e1efe1f 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -262,7 +262,7 @@ static TimestampTz XLogReceiptTime = 0;
 static XLogSource XLogReceiptSource = XLOG_FROM_ANY;
 
 /* Local copy of WalRcv->flushedUpto */
-static XLogRecPtr flushedUpto = 0;
+static XLogRecPtr flushedUpto = InvalidXLogRecPtr;
 static TimeLineID receiveTLI = 0;
 
 /*
@@ -3909,7 +3909,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 						RequestXLogStreaming(tli, ptr, PrimaryConnInfo,
 											 PrimarySlotName,
 											 wal_receiver_create_temp_slot);
-						flushedUpto = 0;
+						flushedUpto = InvalidXLogRecPtr;
 					}
 
 					/*
@@ -4087,7 +4087,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 static int
 emode_for_corrupt_record(int emode, XLogRecPtr RecPtr)
 {
-	static XLogRecPtr lastComplaint = 0;
+	static XLogRecPtr lastComplaint = InvalidXLogRecPtr;
 
 	if (readSource == XLOG_FROM_PG_WAL && emode == LOG)
 	{
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index a0c79958fd5..1f11c8646f5 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -355,7 +355,7 @@ SyncRepWaitForLSN(XLogRecPtr lsn, bool commit)
 	pg_read_barrier();
 	Assert(dlist_node_is_detached(&MyProc->syncRepLinks));
 	MyProc->syncRepState = SYNC_REP_NOT_WAITING;
-	MyProc->waitLSN = 0;
+	MyProc->waitLSN = InvalidXLogRecPtr;
 
 	/* reset ps display to remove the suffix */
 	if (update_process_title)
@@ -1028,7 +1028,7 @@ SyncRepQueueIsOrderedByLSN(int mode)
 
 	Assert(mode >= 0 && mode < NUM_SYNC_REP_WAIT_MODE);
 
-	lastLSN = 0;
+	lastLSN = InvalidXLogRecPtr;
 
 	dlist_foreach(iter, &WalSndCtl->SyncRepQueue[mode])
 	{
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index 4217fc54e2e..3ac5753ff40 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1091,8 +1091,8 @@ XLogWalRcvClose(XLogRecPtr recptr, TimeLineID tli)
 static void
 XLogWalRcvSendReply(bool force, bool requestReply)
 {
-	static XLogRecPtr writePtr = 0;
-	static XLogRecPtr flushPtr = 0;
+	static XLogRecPtr writePtr = InvalidXLogRecPtr;
+	static XLogRecPtr flushPtr = InvalidXLogRecPtr;
 	XLogRecPtr	applyPtr;
 	TimestampTz now;
 
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 1504fafe6d8..ce0d6a7539c 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -509,7 +509,7 @@ InitProcess(void)
 	MyProc->recoveryConflictPending = false;
 
 	/* Initialize fields for sync rep */
-	MyProc->waitLSN = 0;
+	MyProc->waitLSN = InvalidXLogRecPtr;
 	MyProc->syncRepState = SYNC_REP_NOT_WAITING;
 	dlist_node_init(&MyProc->syncRepLinks);
 
diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c
index a31e7643cf0..2c938011144 100644
--- a/src/bin/pg_resetwal/pg_resetwal.c
+++ b/src/bin/pg_resetwal/pg_resetwal.c
@@ -886,10 +886,10 @@ RewriteControlFile(void)
 
 	ControlFile.state = DB_SHUTDOWNED;
 	ControlFile.checkPoint = ControlFile.checkPointCopy.redo;
-	ControlFile.minRecoveryPoint = 0;
+	ControlFile.minRecoveryPoint = InvalidXLogRecPtr;
 	ControlFile.minRecoveryPointTLI = 0;
-	ControlFile.backupStartPoint = 0;
-	ControlFile.backupEndPoint = 0;
+	ControlFile.backupStartPoint = InvalidXLogRecPtr;
+	ControlFile.backupEndPoint = InvalidXLogRecPtr;
 	ControlFile.backupEndRequired = false;
 
 	/*
@@ -1120,7 +1120,7 @@ WriteEmptyXLOG(void)
 	/* Insert the initial checkpoint record */
 	recptr = (char *) page + SizeOfXLogLongPHD;
 	record = (XLogRecord *) recptr;
-	record->xl_prev = 0;
+	record->xl_prev = InvalidXLogRecPtr;
 	record->xl_xid = InvalidTransactionId;
 	record->xl_tot_len = SizeOfXLogRecord + SizeOfXLogRecordDataHeaderShort + sizeof(CheckPoint);
 	record->xl_info = XLOG_CHECKPOINT_SHUTDOWN;
diff --git a/src/bin/pg_rewind/pg_rewind.c b/src/bin/pg_rewind/pg_rewind.c
index 27c514f934a..f92fe37bc20 100644
--- a/src/bin/pg_rewind/pg_rewind.c
+++ b/src/bin/pg_rewind/pg_rewind.c
@@ -375,7 +375,7 @@ main(int argc, char **argv)
 	{
 		pg_log_info("source and target cluster are on the same timeline");
 		rewind_needed = false;
-		target_wal_endrec = 0;
+		target_wal_endrec = InvalidXLogRecPtr;
 	}
 	else
 	{
-- 
2.34.1

#32Bertrand Drouvot
bertranddrouvot.pg@gmail.com
In reply to: Bertrand Drouvot (#31)
1 attachment(s)
Re: Consistently use the XLogRecPtrIsInvalid() macro

Hi,

On Mon, Nov 17, 2025 at 01:12:24PM +0000, Bertrand Drouvot wrote:

The script has been updated and the patch too (finding a new replacement in
gist.c).

Finally, adding GistNSN to the game (as a typedef XLogRecPtr) gives the attached.

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

Attachments:

v10-0001-Replace-literal-0-with-InvalidXLogRecPtr-for-XLo.patchtext/x-diff; charset=us-asciiDownload
From dae57e2823b244c0fbe495d2c32cea525052b05b Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Mon, 17 Nov 2025 12:28:51 +0000
Subject: [PATCH v10] Replace literal 0 with InvalidXLogRecPtr for XLogRecPtr
 assignments

Use the proper constant InvalidXLogRecPtr instead of literal 0 when
assigning XLogRecPtr variables and struct fields.

This improves code clarity by making it explicit that these are
invalid LSN values rather than ambiguous zero literals.
---
 src/backend/access/gist/gist.c              | 4 ++--
 src/backend/access/transam/parallel.c       | 4 ++--
 src/backend/access/transam/xlog.c           | 6 +++---
 src/backend/access/transam/xlogprefetcher.c | 2 +-
 src/backend/access/transam/xlogrecovery.c   | 6 +++---
 src/backend/replication/syncrep.c           | 4 ++--
 src/backend/replication/walreceiver.c       | 4 ++--
 src/backend/storage/lmgr/proc.c             | 2 +-
 src/bin/pg_resetwal/pg_resetwal.c           | 8 ++++----
 src/bin/pg_rewind/pg_rewind.c               | 2 +-
 10 files changed, 21 insertions(+), 21 deletions(-)
   8.0% src/backend/access/gist/
  44.0% src/backend/access/transam/
  18.1% src/backend/replication/
   4.0% src/backend/storage/lmgr/
  21.2% src/bin/pg_resetwal/
   4.4% src/bin/pg_rewind/

diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c
index 3fb1a1285c5..9c9580950f5 100644
--- a/src/backend/access/gist/gist.c
+++ b/src/backend/access/gist/gist.c
@@ -290,7 +290,7 @@ gistplacetopage(Relation rel, Size freespace, GISTSTATE *giststate,
 		SplitPageLayout *dist = NULL,
 				   *ptr;
 		BlockNumber oldrlink = InvalidBlockNumber;
-		GistNSN		oldnsn = 0;
+		GistNSN oldnsn = InvalidXLogRecPtr;
 		SplitPageLayout rootpg;
 		bool		is_rootsplit;
 		int			npage;
@@ -653,7 +653,7 @@ gistdoinsert(Relation r, IndexTuple itup, Size freespace,
 
 	/* Start from the root */
 	firststack.blkno = GIST_ROOT_BLKNO;
-	firststack.lsn = 0;
+	firststack.lsn = InvalidXLogRecPtr;
 	firststack.retry_from_parent = false;
 	firststack.parent = NULL;
 	firststack.downlinkoffnum = InvalidOffsetNumber;
diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index 94db1ec3012..14ef12a4dd5 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -356,7 +356,7 @@ InitializeParallelDSM(ParallelContext *pcxt)
 	fps->stmt_ts = GetCurrentStatementStartTimestamp();
 	fps->serializable_xact_handle = ShareSerializableXact();
 	SpinLockInit(&fps->mutex);
-	fps->last_xlog_end = 0;
+	fps->last_xlog_end = InvalidXLogRecPtr;
 	shm_toc_insert(pcxt->toc, PARALLEL_KEY_FIXED, fps);
 
 	/* We can skip the rest of this if we're not budgeting for any workers. */
@@ -525,7 +525,7 @@ ReinitializeParallelDSM(ParallelContext *pcxt)
 
 	/* Reset a few bits of fixed parallel state to a clean state. */
 	fps = shm_toc_lookup(pcxt->toc, PARALLEL_KEY_FIXED, false);
-	fps->last_xlog_end = 0;
+	fps->last_xlog_end = InvalidXLogRecPtr;
 
 	/* Recreate error queues (if they exist). */
 	if (pcxt->nworkers > 0)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 22d0a2e8c3a..f5cb9313f11 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -2060,7 +2060,7 @@ AdvanceXLInsertBuffer(XLogRecPtr upto, TimeLineID tli, bool opportunistic)
 					/* Have to write it ourselves */
 					TRACE_POSTGRESQL_WAL_BUFFER_WRITE_DIRTY_START();
 					WriteRqst.Write = OldPageRqstPtr;
-					WriteRqst.Flush = 0;
+					WriteRqst.Flush = InvalidXLogRecPtr;
 					XLogWrite(WriteRqst, tli, false);
 					LWLockRelease(WALWriteLock);
 					pgWalUsage.wal_buffers_full++;
@@ -3067,7 +3067,7 @@ XLogBackgroundFlush(void)
 	else
 	{
 		/* no flushing, this time round */
-		WriteRqst.Flush = 0;
+		WriteRqst.Flush = InvalidXLogRecPtr;
 	}
 
 #ifdef WAL_DEBUG
@@ -5171,7 +5171,7 @@ BootStrapXLOG(uint32 data_checksum_version)
 	/* Insert the initial checkpoint record */
 	recptr = ((char *) page + SizeOfXLogLongPHD);
 	record = (XLogRecord *) recptr;
-	record->xl_prev = 0;
+	record->xl_prev = InvalidXLogRecPtr;
 	record->xl_xid = InvalidTransactionId;
 	record->xl_tot_len = SizeOfXLogRecord + SizeOfXLogRecordDataHeaderShort + sizeof(checkPoint);
 	record->xl_info = XLOG_CHECKPOINT_SHUTDOWN;
diff --git a/src/backend/access/transam/xlogprefetcher.c b/src/backend/access/transam/xlogprefetcher.c
index ed3aacabc98..a1ef603f5f9 100644
--- a/src/backend/access/transam/xlogprefetcher.c
+++ b/src/backend/access/transam/xlogprefetcher.c
@@ -967,7 +967,7 @@ XLogPrefetcherBeginRead(XLogPrefetcher *prefetcher, XLogRecPtr recPtr)
 	/* Book-keeping to avoid readahead on first read. */
 	prefetcher->begin_ptr = recPtr;
 
-	prefetcher->no_readahead_until = 0;
+	prefetcher->no_readahead_until = InvalidXLogRecPtr;
 
 	/* This will forget about any queued up records in the decoder. */
 	XLogBeginRead(prefetcher->reader, recPtr);
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index 21b8f179ba0..3237e1efe1f 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -262,7 +262,7 @@ static TimestampTz XLogReceiptTime = 0;
 static XLogSource XLogReceiptSource = XLOG_FROM_ANY;
 
 /* Local copy of WalRcv->flushedUpto */
-static XLogRecPtr flushedUpto = 0;
+static XLogRecPtr flushedUpto = InvalidXLogRecPtr;
 static TimeLineID receiveTLI = 0;
 
 /*
@@ -3909,7 +3909,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 						RequestXLogStreaming(tli, ptr, PrimaryConnInfo,
 											 PrimarySlotName,
 											 wal_receiver_create_temp_slot);
-						flushedUpto = 0;
+						flushedUpto = InvalidXLogRecPtr;
 					}
 
 					/*
@@ -4087,7 +4087,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 static int
 emode_for_corrupt_record(int emode, XLogRecPtr RecPtr)
 {
-	static XLogRecPtr lastComplaint = 0;
+	static XLogRecPtr lastComplaint = InvalidXLogRecPtr;
 
 	if (readSource == XLOG_FROM_PG_WAL && emode == LOG)
 	{
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index a0c79958fd5..1f11c8646f5 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -355,7 +355,7 @@ SyncRepWaitForLSN(XLogRecPtr lsn, bool commit)
 	pg_read_barrier();
 	Assert(dlist_node_is_detached(&MyProc->syncRepLinks));
 	MyProc->syncRepState = SYNC_REP_NOT_WAITING;
-	MyProc->waitLSN = 0;
+	MyProc->waitLSN = InvalidXLogRecPtr;
 
 	/* reset ps display to remove the suffix */
 	if (update_process_title)
@@ -1028,7 +1028,7 @@ SyncRepQueueIsOrderedByLSN(int mode)
 
 	Assert(mode >= 0 && mode < NUM_SYNC_REP_WAIT_MODE);
 
-	lastLSN = 0;
+	lastLSN = InvalidXLogRecPtr;
 
 	dlist_foreach(iter, &WalSndCtl->SyncRepQueue[mode])
 	{
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index 4217fc54e2e..3ac5753ff40 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1091,8 +1091,8 @@ XLogWalRcvClose(XLogRecPtr recptr, TimeLineID tli)
 static void
 XLogWalRcvSendReply(bool force, bool requestReply)
 {
-	static XLogRecPtr writePtr = 0;
-	static XLogRecPtr flushPtr = 0;
+	static XLogRecPtr writePtr = InvalidXLogRecPtr;
+	static XLogRecPtr flushPtr = InvalidXLogRecPtr;
 	XLogRecPtr	applyPtr;
 	TimestampTz now;
 
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 1504fafe6d8..ce0d6a7539c 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -509,7 +509,7 @@ InitProcess(void)
 	MyProc->recoveryConflictPending = false;
 
 	/* Initialize fields for sync rep */
-	MyProc->waitLSN = 0;
+	MyProc->waitLSN = InvalidXLogRecPtr;
 	MyProc->syncRepState = SYNC_REP_NOT_WAITING;
 	dlist_node_init(&MyProc->syncRepLinks);
 
diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c
index a31e7643cf0..2c938011144 100644
--- a/src/bin/pg_resetwal/pg_resetwal.c
+++ b/src/bin/pg_resetwal/pg_resetwal.c
@@ -886,10 +886,10 @@ RewriteControlFile(void)
 
 	ControlFile.state = DB_SHUTDOWNED;
 	ControlFile.checkPoint = ControlFile.checkPointCopy.redo;
-	ControlFile.minRecoveryPoint = 0;
+	ControlFile.minRecoveryPoint = InvalidXLogRecPtr;
 	ControlFile.minRecoveryPointTLI = 0;
-	ControlFile.backupStartPoint = 0;
-	ControlFile.backupEndPoint = 0;
+	ControlFile.backupStartPoint = InvalidXLogRecPtr;
+	ControlFile.backupEndPoint = InvalidXLogRecPtr;
 	ControlFile.backupEndRequired = false;
 
 	/*
@@ -1120,7 +1120,7 @@ WriteEmptyXLOG(void)
 	/* Insert the initial checkpoint record */
 	recptr = (char *) page + SizeOfXLogLongPHD;
 	record = (XLogRecord *) recptr;
-	record->xl_prev = 0;
+	record->xl_prev = InvalidXLogRecPtr;
 	record->xl_xid = InvalidTransactionId;
 	record->xl_tot_len = SizeOfXLogRecord + SizeOfXLogRecordDataHeaderShort + sizeof(CheckPoint);
 	record->xl_info = XLOG_CHECKPOINT_SHUTDOWN;
diff --git a/src/bin/pg_rewind/pg_rewind.c b/src/bin/pg_rewind/pg_rewind.c
index 27c514f934a..f92fe37bc20 100644
--- a/src/bin/pg_rewind/pg_rewind.c
+++ b/src/bin/pg_rewind/pg_rewind.c
@@ -375,7 +375,7 @@ main(int argc, char **argv)
 	{
 		pg_log_info("source and target cluster are on the same timeline");
 		rewind_needed = false;
-		target_wal_endrec = 0;
+		target_wal_endrec = InvalidXLogRecPtr;
 	}
 	else
 	{
-- 
2.34.1

#33Bertrand Drouvot
bertranddrouvot.pg@gmail.com
In reply to: Bertrand Drouvot (#23)
8 attachment(s)
Re: Consistently use the XLogRecPtrIsInvalid() macro

Hi,

On Fri, Nov 07, 2025 at 03:03:03PM +0000, Bertrand Drouvot wrote:

I'm currently working on the RegProcedureIsValid() and OidIsValid() cases,
will share once done.

here they are, I'm not creating a new thread for those as this is the same
kind of ideas (but for other types) but can create a dedicated one if you prefer.

That's a lot of changes so it is split in multiple patches to ease the review:

0001: makes use of RegProcedureIsValid() instead of direct comparisons with
InvalidOid or literal 0. That leads to some implicit boolean conversion to be
replaced by RegProcedureIsValid() checks. There are no literal 0 assignments on
RegProcedure type.

0002: makes use of OidIsValid() instead of direct comparisons with InvalidOid
or literal 0. That leads to some implicit boolean conversion to be replaced by
OidIsValid() checks. It covers the majority of cases.

0003: same as 0002 but for pointers/array.

0004: same as 0002 but for CATALOG (FormData_xxx) structs.

0005: same as 0002 but for functions returning Oid.

0006: same as 0002 but for remaining edge cases that have been done manually.

0007: replace ternary operators with !OidIsValid() rnd negated OidIsValid
equality to use positive logic.

0008: replace literal 0 with InvalidOid for Oid assignments.

Remarks:

- those patches (except 0006) have been generated using the .cocci scripts in
[1]: https://github.com/bdrouvot/coccinelle_on_pg/tree/main/InvalidOid
the script header).

- comments are not changed, so there is still a few that contains "== InvalidOid"
while the underlying code is now using OidIsValid(). We may want to change
the comments too. I don't have a strong opinion on it just a small preference
to change the comments too. Thoughts?

Please note that, once the patch is applied, there is one InvalidOid direct
comparison done that is not on "Oid" or "RegProcedure" types:

$ git grep "!= InvalidOid"
src/backend/storage/lmgr/lock.c: (locktag)->locktag_field1 != InvalidOid && \

I think this one should be replaced by != 0 instead because:

- locktag_field1 is uint32 (not RegProcedure or Oid)
- it can be assigned non Oid values (like xid, procNumber)

"
src/include/storage/lock.h: uint32 locktag_field1; /* a 32-bit ID field */
src/include/storage/lock.h: ((locktag).locktag_field1 = (dboid), \
src/include/storage/lock.h: ((locktag).locktag_field1 = (dboid), \
src/include/storage/lock.h: ((locktag).locktag_field1 = (dboid), \
src/include/storage/lock.h: ((locktag).locktag_field1 = (dboid), \
src/include/storage/lock.h: ((locktag).locktag_field1 = (dboid), \
src/include/storage/lock.h: ((locktag).locktag_field1 = (xid), \
src/include/storage/lock.h: ((locktag).locktag_field1 = (vxid).procNumber, \
src/include/storage/lock.h: ((locktag).locktag_field1 = (xid), \
src/include/storage/lock.h: ((locktag).locktag_field1 = (dboid), \
src/include/storage/lock.h: ((locktag).locktag_field1 = (id1), \
src/include/storage/lock.h: ((locktag).locktag_field1 = (dboid), \
"

While the direct comparison to InvalidOid is technically correct, it is
confusing semantically because the field doesn't always contain an OID value.

I'll now look at the TransactionIdIsValid() cases.

[1]: https://github.com/bdrouvot/coccinelle_on_pg/tree/main/InvalidOid

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

Attachments:

v1-0001-Use-RegProcedureIsValid-in-various-places.patchtext/x-diff; charset=us-asciiDownload
From 18f69a7269a32206ba6fea58508ae30e49605340 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Sat, 8 Nov 2025 03:35:35 +0000
Subject: [PATCH v1 1/8] Use RegProcedureIsValid() in various places

Let's use RegProcedureIsValid() instead of:

- direct comparisons with InvalidOid
- direct comparisons with literal 0

This makes the code more consistent (same idea as a2b02293bc6).
---
 src/backend/access/gin/ginutil.c     | 8 ++++----
 src/backend/optimizer/util/plancat.c | 6 +++---
 src/backend/utils/adt/regproc.c      | 4 ++--
 src/backend/utils/adt/selfuncs.c     | 2 +-
 4 files changed, 10 insertions(+), 10 deletions(-)
  65.1% src/backend/access/gin/
  16.8% src/backend/optimizer/util/
  17.9% src/backend/utils/adt/

diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c
index 78f7b7a2495..49631200a5a 100644
--- a/src/backend/access/gin/ginutil.c
+++ b/src/backend/access/gin/ginutil.c
@@ -134,7 +134,7 @@ initGinState(GinState *state, Relation index)
 		 * If the compare proc isn't specified in the opclass definition, look
 		 * up the index key type's default btree comparator.
 		 */
-		if (index_getprocid(index, i + 1, GIN_COMPARE_PROC) != InvalidOid)
+		if (RegProcedureIsValid(index_getprocid(index, i + 1, GIN_COMPARE_PROC)))
 		{
 			fmgr_info_copy(&(state->compareFn[i]),
 						   index_getprocinfo(index, i + 1, GIN_COMPARE_PROC),
@@ -168,14 +168,14 @@ initGinState(GinState *state, Relation index)
 		 * Check opclass capability to do tri-state or binary logic consistent
 		 * check.
 		 */
-		if (index_getprocid(index, i + 1, GIN_TRICONSISTENT_PROC) != InvalidOid)
+		if (RegProcedureIsValid(index_getprocid(index, i + 1, GIN_TRICONSISTENT_PROC)))
 		{
 			fmgr_info_copy(&(state->triConsistentFn[i]),
 						   index_getprocinfo(index, i + 1, GIN_TRICONSISTENT_PROC),
 						   CurrentMemoryContext);
 		}
 
-		if (index_getprocid(index, i + 1, GIN_CONSISTENT_PROC) != InvalidOid)
+		if (RegProcedureIsValid(index_getprocid(index, i + 1, GIN_CONSISTENT_PROC)))
 		{
 			fmgr_info_copy(&(state->consistentFn[i]),
 						   index_getprocinfo(index, i + 1, GIN_CONSISTENT_PROC),
@@ -193,7 +193,7 @@ initGinState(GinState *state, Relation index)
 		/*
 		 * Check opclass capability to do partial match.
 		 */
-		if (index_getprocid(index, i + 1, GIN_COMPARE_PARTIAL_PROC) != InvalidOid)
+		if (RegProcedureIsValid(index_getprocid(index, i + 1, GIN_COMPARE_PARTIAL_PROC)))
 		{
 			fmgr_info_copy(&(state->comparePartialFn[i]),
 						   index_getprocinfo(index, i + 1, GIN_COMPARE_PARTIAL_PROC),
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index d950bd93002..a01f781bca8 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -2088,7 +2088,7 @@ restriction_selectivity(PlannerInfo *root,
 	 * if the oprrest procedure is missing for whatever reason, use a
 	 * selectivity of 0.5
 	 */
-	if (!oprrest)
+	if (!RegProcedureIsValid(oprrest))
 		return (Selectivity) 0.5;
 
 	result = DatumGetFloat8(OidFunctionCall4Coll(oprrest,
@@ -2128,7 +2128,7 @@ join_selectivity(PlannerInfo *root,
 	 * if the oprjoin procedure is missing for whatever reason, use a
 	 * selectivity of 0.5
 	 */
-	if (!oprjoin)
+	if (!RegProcedureIsValid(oprjoin))
 		return (Selectivity) 0.5;
 
 	result = DatumGetFloat8(OidFunctionCall5Coll(oprjoin,
@@ -2167,7 +2167,7 @@ function_selectivity(PlannerInfo *root,
 	SupportRequestSelectivity req;
 	SupportRequestSelectivity *sresult;
 
-	if (!prosupport)
+	if (!RegProcedureIsValid(prosupport))
 		return (Selectivity) -1;	/* no support function */
 
 	req.type = T_SupportRequestSelectivity;
diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c
index e5c2246f2c9..7ce61efd947 100644
--- a/src/backend/utils/adt/regproc.c
+++ b/src/backend/utils/adt/regproc.c
@@ -142,7 +142,7 @@ regprocout(PG_FUNCTION_ARGS)
 	char	   *result;
 	HeapTuple	proctup;
 
-	if (proid == InvalidOid)
+	if (!RegProcedureIsValid(proid))
 	{
 		result = pstrdup("-");
 		PG_RETURN_CSTRING(result);
@@ -443,7 +443,7 @@ regprocedureout(PG_FUNCTION_ARGS)
 	RegProcedure proid = PG_GETARG_OID(0);
 	char	   *result;
 
-	if (proid == InvalidOid)
+	if (!RegProcedureIsValid(proid))
 		result = pstrdup("-");
 	else
 		result = format_procedure(proid);
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index cb23ad52782..911376f79e8 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -1904,7 +1904,7 @@ scalararraysel(PlannerInfo *root,
 		oprsel = get_oprjoin(operator);
 	else
 		oprsel = get_oprrest(operator);
-	if (!oprsel)
+	if (!RegProcedureIsValid(oprsel))
 		return (Selectivity) 0.5;
 	fmgr_info(oprsel, &oprselproc);
 
-- 
2.34.1

v1-0002-Use-OidIsValid-in-various-places.patchtext/x-diff; charset=us-asciiDownload
From 54faaa30643da0ad55c11b9b0c10b8b08c709051 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Sat, 15 Nov 2025 17:24:49 +0000
Subject: [PATCH v1 2/8] Use OidIsValid() in various places

Let's use OidIsValid() instead of:

- direct comparisons with InvalidOid
- direct comparisons with literal 0
---
 contrib/pg_overexplain/pg_overexplain.c       |  2 +-
 contrib/pg_prewarm/autoprewarm.c              |  6 +--
 .../pg_stat_statements/pg_stat_statements.c   |  8 ++--
 contrib/postgres_fdw/deparse.c                | 32 +++++++--------
 src/backend/access/brin/brin.c                |  2 +-
 src/backend/access/brin/brin_bloom.c          |  2 +-
 src/backend/access/brin/brin_inclusion.c      |  4 +-
 src/backend/access/brin/brin_minmax.c         |  2 +-
 src/backend/access/brin/brin_minmax_multi.c   |  6 +--
 src/backend/access/common/toast_internals.c   |  2 +-
 src/backend/access/gin/gininsert.c            |  2 +-
 src/backend/access/gin/ginutil.c              |  4 +-
 src/backend/access/gist/gistutil.c            |  4 +-
 src/backend/access/hash/hashfunc.c            |  4 +-
 src/backend/access/hash/hashsearch.c          |  2 +-
 src/backend/access/heap/heapam.c              |  2 +-
 src/backend/access/heap/heapam_visibility.c   | 16 ++++----
 src/backend/access/index/indexam.c            |  2 +-
 src/backend/access/nbtree/nbtcompare.c        |  2 +-
 src/backend/access/nbtree/nbtpreprocesskeys.c | 18 ++++-----
 src/backend/access/nbtree/nbtsearch.c         |  2 +-
 src/backend/access/table/tableamapi.c         |  2 +-
 src/backend/bootstrap/bootstrap.c             |  2 +-
 src/backend/catalog/aclchk.c                  |  3 +-
 src/backend/catalog/catalog.c                 |  2 +-
 src/backend/catalog/heap.c                    | 12 +++---
 src/backend/catalog/index.c                   |  2 +-
 src/backend/catalog/namespace.c               |  4 +-
 src/backend/catalog/objectaddress.c           |  4 +-
 src/backend/catalog/partition.c               |  2 +-
 src/backend/catalog/pg_aggregate.c            |  2 +-
 src/backend/catalog/pg_inherits.c             |  4 +-
 src/backend/catalog/pg_operator.c             |  6 +--
 src/backend/catalog/pg_shdepend.c             |  2 +-
 src/backend/catalog/pg_tablespace.c           |  2 +-
 src/backend/catalog/toasting.c                |  2 +-
 src/backend/commands/aggregatecmds.c          |  2 +-
 src/backend/commands/cluster.c                |  2 +-
 src/backend/commands/copyto.c                 |  2 +-
 src/backend/commands/event_trigger.c          |  2 +-
 src/backend/commands/extension.c              |  2 +-
 src/backend/commands/functioncmds.c           |  4 +-
 src/backend/commands/indexcmds.c              | 12 +++---
 src/backend/commands/sequence.c               |  4 +-
 src/backend/commands/statscmds.c              |  6 +--
 src/backend/commands/tablecmds.c              | 22 +++++-----
 src/backend/commands/tablespace.c             |  8 ++--
 src/backend/commands/trigger.c                |  2 +-
 src/backend/commands/typecmds.c               | 18 ++++-----
 src/backend/commands/vacuum.c                 |  2 +-
 src/backend/commands/view.c                   |  2 +-
 src/backend/executor/execUtils.c              |  2 +-
 src/backend/executor/functions.c              |  2 +-
 src/backend/nodes/nodeFuncs.c                 |  8 ++--
 src/backend/optimizer/path/costsize.c         |  4 +-
 src/backend/optimizer/path/indxpath.c         |  6 +--
 src/backend/optimizer/path/joinpath.c         |  2 +-
 src/backend/optimizer/prep/prepqual.c         |  4 +-
 src/backend/optimizer/util/plancat.c          | 20 +++++-----
 src/backend/parser/parse_clause.c             |  2 +-
 src/backend/parser/parse_coerce.c             |  6 +--
 src/backend/parser/parse_expr.c               |  6 +--
 src/backend/parser/parse_oper.c               | 10 ++---
 src/backend/parser/parse_target.c             |  2 +-
 src/backend/parser/parse_type.c               |  2 +-
 src/backend/parser/parse_utilcmd.c            |  4 +-
 .../libpqwalreceiver/libpqwalreceiver.c       |  2 +-
 src/backend/replication/logical/decode.c      |  2 +-
 src/backend/replication/logical/logical.c     |  2 +-
 src/backend/replication/logical/relation.c    |  4 +-
 .../replication/logical/reorderbuffer.c       |  4 +-
 src/backend/replication/pgoutput/pgoutput.c   |  2 +-
 src/backend/replication/slot.c                |  4 +-
 src/backend/replication/slotfuncs.c           |  6 +--
 src/backend/replication/walsender.c           |  8 ++--
 src/backend/rewrite/rewriteHandler.c          |  2 +-
 src/backend/statistics/dependencies.c         |  2 +-
 src/backend/statistics/mcv.c                  |  2 +-
 src/backend/statistics/mvdistinct.c           |  2 +-
 src/backend/storage/buffer/bufmgr.c           |  2 +-
 src/backend/storage/file/fd.c                 |  4 +-
 src/backend/storage/ipc/procarray.c           |  4 +-
 src/backend/storage/lmgr/lock.c               |  2 +-
 src/backend/storage/lmgr/predicate.c          |  2 +-
 src/backend/tcop/postgres.c                   |  2 +-
 src/backend/tsearch/ts_parse.c                |  2 +-
 src/backend/utils/activity/pgstat.c           |  2 +-
 src/backend/utils/adt/array_selfuncs.c        |  2 +-
 src/backend/utils/adt/array_userfuncs.c       |  4 +-
 src/backend/utils/adt/enum.c                  |  8 ++--
 src/backend/utils/adt/format_type.c           |  4 +-
 src/backend/utils/adt/json.c                  | 10 ++---
 src/backend/utils/adt/jsonb.c                 | 10 ++---
 src/backend/utils/adt/like_support.c          |  2 +-
 src/backend/utils/adt/misc.c                  |  8 ++--
 .../utils/adt/multirangetypes_selfuncs.c      |  2 +-
 src/backend/utils/adt/network.c               |  4 +-
 src/backend/utils/adt/pgstatfuncs.c           |  4 +-
 src/backend/utils/adt/rangetypes_selfuncs.c   |  2 +-
 src/backend/utils/adt/regproc.c               | 20 +++++-----
 src/backend/utils/adt/ruleutils.c             |  4 +-
 src/backend/utils/adt/selfuncs.c              |  8 ++--
 src/backend/utils/adt/varchar.c               |  4 +-
 src/backend/utils/cache/inval.c               | 14 +++----
 src/backend/utils/cache/lsyscache.c           |  2 +-
 src/backend/utils/cache/plancache.c           |  6 +--
 src/backend/utils/cache/relfilenumbermap.c    |  4 +-
 src/backend/utils/cache/spccache.c            |  2 +-
 src/backend/utils/cache/ts_cache.c            |  2 +-
 src/backend/utils/cache/typcache.c            | 40 +++++++++----------
 src/backend/utils/fmgr/funcapi.c              |  2 +-
 src/backend/utils/misc/queryenvironment.c     |  2 +-
 src/bin/pg_dump/common.c                      |  2 +-
 src/bin/pg_dump/pg_backup_archiver.c          |  2 +-
 src/bin/pg_dump/pg_backup_custom.c            |  6 +--
 src/bin/pg_dump/pg_backup_null.c              |  2 +-
 src/bin/pg_dump/pg_backup_tar.c               |  4 +-
 src/bin/pg_dump/pg_dump.c                     | 24 +++++------
 src/bin/pg_resetwal/pg_resetwal.c             |  6 +--
 src/bin/psql/describe.c                       |  2 +-
 src/bin/psql/large_obj.c                      |  2 +-
 src/common/relpath.c                          |  4 +-
 src/interfaces/libpq/fe-lobj.c                | 30 +++++++-------
 src/pl/plperl/plperl.c                        | 12 +++---
 src/pl/plpgsql/src/pl_exec.c                  |  4 +-
 src/pl/plpython/plpy_procedure.c              |  2 +-
 src/pl/plpython/plpy_typeio.c                 |  8 +---
 src/test/examples/testlo.c                    |  4 +-
 src/test/examples/testlo64.c                  |  4 +-
 129 files changed, 346 insertions(+), 349 deletions(-)
   3.8% contrib/postgres_fdw/
   3.3% src/backend/access/brin/
   8.4% src/backend/access/
   7.5% src/backend/catalog/
  15.7% src/backend/commands/
   3.0% src/backend/optimizer/util/
   4.5% src/backend/parser/
   4.6% src/backend/replication/
   9.9% src/backend/utils/adt/
  11.3% src/backend/utils/cache/
   9.4% src/backend/
   4.3% src/bin/pg_dump/
   4.1% src/interfaces/libpq/
   4.7% src/pl/

diff --git a/contrib/pg_overexplain/pg_overexplain.c b/contrib/pg_overexplain/pg_overexplain.c
index bd70b6d9d5e..ebf8109ec84 100644
--- a/contrib/pg_overexplain/pg_overexplain.c
+++ b/contrib/pg_overexplain/pg_overexplain.c
@@ -479,7 +479,7 @@ overexplain_range_table(PlannedStmt *plannedstmt, ExplainState *es)
 		 * displayed only in verbose mode, and we emit nothing if there is no
 		 * relation OID.
 		 */
-		if (rte->relid != 0)
+		if (OidIsValid(rte->relid))
 		{
 			const char *relname;
 			const char *qualname;
diff --git a/contrib/pg_prewarm/autoprewarm.c b/contrib/pg_prewarm/autoprewarm.c
index 5ba1240d51f..837fe43f937 100644
--- a/contrib/pg_prewarm/autoprewarm.c
+++ b/contrib/pg_prewarm/autoprewarm.c
@@ -398,7 +398,7 @@ apw_load_buffers(void)
 				 * Combine BlockInfoRecords for global objects with those of
 				 * the database.
 				 */
-				if (current_db != InvalidOid)
+				if (OidIsValid(current_db))
 					break;
 				current_db = blkinfo[j].database;
 			}
@@ -411,7 +411,7 @@ apw_load_buffers(void)
 		 * BlockInfoRecords belonging to global objects exist.  We can't
 		 * prewarm without a database connection, so just bail out.
 		 */
-		if (current_db == InvalidOid)
+		if (!OidIsValid(current_db))
 			break;
 
 		/* Configure stop point and database for next per-database worker. */
@@ -536,7 +536,7 @@ autoprewarm_database_main(Datum main_arg)
 		 * All blocks between prewarm_start_idx and prewarm_stop_idx should
 		 * belong either to global objects or the same database.
 		 */
-		Assert(blk.database == apw_state->database || blk.database == 0);
+		Assert(blk.database == apw_state->database || !OidIsValid(blk.database));
 
 		StartTransactionCommand();
 
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 39208f80b5b..83ac02f2f0e 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -2730,7 +2730,7 @@ entry_reset(Oid userid, Oid dbid, int64 queryid, bool minmax_only)
 
 	stats_reset = GetCurrentTimestamp();
 
-	if (userid != 0 && dbid != 0 && queryid != INT64CONST(0))
+	if (OidIsValid(userid) && OidIsValid(dbid) && queryid != INT64CONST(0))
 	{
 		/* If all the parameters are available, use the fast path. */
 		memset(&key, 0, sizeof(pgssHashKey));
@@ -2753,14 +2753,14 @@ entry_reset(Oid userid, Oid dbid, int64 queryid, bool minmax_only)
 
 		SINGLE_ENTRY_RESET(entry);
 	}
-	else if (userid != 0 || dbid != 0 || queryid != INT64CONST(0))
+	else if (OidIsValid(userid) || OidIsValid(dbid) || queryid != INT64CONST(0))
 	{
 		/* Reset entries corresponding to valid parameters. */
 		hash_seq_init(&hash_seq, pgss_hash);
 		while ((entry = hash_seq_search(&hash_seq)) != NULL)
 		{
-			if ((!userid || entry->key.userid == userid) &&
-				(!dbid || entry->key.dbid == dbid) &&
+			if ((!OidIsValid(userid) || entry->key.userid == userid) &&
+				(!OidIsValid(dbid) || entry->key.dbid == dbid) &&
 				(!queryid || entry->key.queryid == queryid))
 			{
 				SINGLE_ENTRY_RESET(entry);
diff --git a/contrib/postgres_fdw/deparse.c b/contrib/postgres_fdw/deparse.c
index f2fb0051843..f2b8968c189 100644
--- a/contrib/postgres_fdw/deparse.c
+++ b/contrib/postgres_fdw/deparse.c
@@ -367,7 +367,7 @@ foreign_expr_walker(Node *node,
 				{
 					/* Var belongs to some other table */
 					collation = var->varcollid;
-					if (collation == InvalidOid ||
+					if (!OidIsValid(collation) ||
 						collation == DEFAULT_COLLATION_OID)
 					{
 						/*
@@ -472,7 +472,7 @@ foreign_expr_walker(Node *node,
 				 * non-collation-sensitive context.
 				 */
 				collation = c->constcollid;
-				if (collation == InvalidOid ||
+				if (!OidIsValid(collation) ||
 					collation == DEFAULT_COLLATION_OID)
 					state = FDW_COLLATE_NONE;
 				else
@@ -503,7 +503,7 @@ foreign_expr_walker(Node *node,
 				 * Collation rule is same as for Consts and non-foreign Vars.
 				 */
 				collation = p->paramcollid;
-				if (collation == InvalidOid ||
+				if (!OidIsValid(collation) ||
 					collation == DEFAULT_COLLATION_OID)
 					state = FDW_COLLATE_NONE;
 				else
@@ -543,7 +543,7 @@ foreign_expr_walker(Node *node,
 				 * function nodes.
 				 */
 				collation = sr->refcollid;
-				if (collation == InvalidOid)
+				if (!OidIsValid(collation))
 					state = FDW_COLLATE_NONE;
 				else if (inner_cxt.state == FDW_COLLATE_SAFE &&
 						 collation == inner_cxt.collation)
@@ -577,7 +577,7 @@ foreign_expr_walker(Node *node,
 				 * If function's input collation is not derived from a foreign
 				 * Var, it can't be sent to remote.
 				 */
-				if (fe->inputcollid == InvalidOid)
+				if (!OidIsValid(fe->inputcollid))
 					 /* OK, inputs are all noncollatable */ ;
 				else if (inner_cxt.state != FDW_COLLATE_SAFE ||
 						 fe->inputcollid != inner_cxt.collation)
@@ -590,7 +590,7 @@ foreign_expr_walker(Node *node,
 				 * node might not care.)
 				 */
 				collation = fe->funccollid;
-				if (collation == InvalidOid)
+				if (!OidIsValid(collation))
 					state = FDW_COLLATE_NONE;
 				else if (inner_cxt.state == FDW_COLLATE_SAFE &&
 						 collation == inner_cxt.collation)
@@ -625,7 +625,7 @@ foreign_expr_walker(Node *node,
 				 * If operator's input collation is not derived from a foreign
 				 * Var, it can't be sent to remote.
 				 */
-				if (oe->inputcollid == InvalidOid)
+				if (!OidIsValid(oe->inputcollid))
 					 /* OK, inputs are all noncollatable */ ;
 				else if (inner_cxt.state != FDW_COLLATE_SAFE ||
 						 oe->inputcollid != inner_cxt.collation)
@@ -633,7 +633,7 @@ foreign_expr_walker(Node *node,
 
 				/* Result-collation handling is same as for functions */
 				collation = oe->opcollid;
-				if (collation == InvalidOid)
+				if (!OidIsValid(collation))
 					state = FDW_COLLATE_NONE;
 				else if (inner_cxt.state == FDW_COLLATE_SAFE &&
 						 collation == inner_cxt.collation)
@@ -665,7 +665,7 @@ foreign_expr_walker(Node *node,
 				 * If operator's input collation is not derived from a foreign
 				 * Var, it can't be sent to remote.
 				 */
-				if (oe->inputcollid == InvalidOid)
+				if (!OidIsValid(oe->inputcollid))
 					 /* OK, inputs are all noncollatable */ ;
 				else if (inner_cxt.state != FDW_COLLATE_SAFE ||
 						 oe->inputcollid != inner_cxt.collation)
@@ -692,7 +692,7 @@ foreign_expr_walker(Node *node,
 				 * an input foreign Var (same logic as for a real function).
 				 */
 				collation = r->resultcollid;
-				if (collation == InvalidOid)
+				if (!OidIsValid(collation))
 					state = FDW_COLLATE_NONE;
 				else if (inner_cxt.state == FDW_COLLATE_SAFE &&
 						 collation == inner_cxt.collation)
@@ -720,7 +720,7 @@ foreign_expr_walker(Node *node,
 				 * function).
 				 */
 				collation = e->resultcollid;
-				if (collation == InvalidOid)
+				if (!OidIsValid(collation))
 					state = FDW_COLLATE_NONE;
 				else if (inner_cxt.state == FDW_COLLATE_SAFE &&
 						 collation == inner_cxt.collation)
@@ -846,7 +846,7 @@ foreign_expr_walker(Node *node,
 				 * the THEN and ELSE subexpressions.
 				 */
 				collation = ce->casecollid;
-				if (collation == InvalidOid)
+				if (!OidIsValid(collation))
 					state = FDW_COLLATE_NONE;
 				else if (inner_cxt.state == FDW_COLLATE_SAFE &&
 						 collation == inner_cxt.collation)
@@ -871,7 +871,7 @@ foreign_expr_walker(Node *node,
 				 * the CASE arg.
 				 */
 				collation = c->collation;
-				if (collation == InvalidOid)
+				if (!OidIsValid(collation))
 					state = FDW_COLLATE_NONE;
 				else if (case_arg_cxt->state == FDW_COLLATE_SAFE &&
 						 collation == case_arg_cxt->collation)
@@ -898,7 +898,7 @@ foreign_expr_walker(Node *node,
 				 * an input foreign Var (same logic as for a function).
 				 */
 				collation = a->array_collid;
-				if (collation == InvalidOid)
+				if (!OidIsValid(collation))
 					state = FDW_COLLATE_NONE;
 				else if (inner_cxt.state == FDW_COLLATE_SAFE &&
 						 collation == inner_cxt.collation)
@@ -1010,7 +1010,7 @@ foreign_expr_walker(Node *node,
 				 * If aggregate's input collation is not derived from a
 				 * foreign Var, it can't be sent to remote.
 				 */
-				if (agg->inputcollid == InvalidOid)
+				if (!OidIsValid(agg->inputcollid))
 					 /* OK, inputs are all noncollatable */ ;
 				else if (inner_cxt.state != FDW_COLLATE_SAFE ||
 						 agg->inputcollid != inner_cxt.collation)
@@ -1023,7 +1023,7 @@ foreign_expr_walker(Node *node,
 				 * node might not care.)
 				 */
 				collation = agg->aggcollid;
-				if (collation == InvalidOid)
+				if (!OidIsValid(collation))
 					state = FDW_COLLATE_NONE;
 				else if (inner_cxt.state == FDW_COLLATE_SAFE &&
 						 collation == inner_cxt.collation)
diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c
index 2f7d1437919..8d6ad686fbc 100644
--- a/src/backend/access/brin/brin.c
+++ b/src/backend/access/brin/brin.c
@@ -692,7 +692,7 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
 		 * general, so this should be negligible, and repeated repalloc calls
 		 * are not free either.
 		 */
-		if (consistentFn[keyattno - 1].fn_oid == InvalidOid)
+		if (!OidIsValid(consistentFn->fn_oid))
 		{
 			FmgrInfo   *tmp;
 
diff --git a/src/backend/access/brin/brin_bloom.c b/src/backend/access/brin/brin_bloom.c
index 64dbb7b8532..1c91adbf708 100644
--- a/src/backend/access/brin/brin_bloom.c
+++ b/src/backend/access/brin/brin_bloom.c
@@ -726,7 +726,7 @@ bloom_get_procinfo(BrinDesc *bdesc, uint16 attno, uint16 procnum)
 	 */
 	opaque = (BloomOpaque *) bdesc->bd_info[attno - 1]->oi_opaque;
 
-	if (opaque->extra_procinfos[basenum].fn_oid == InvalidOid)
+	if (!OidIsValid(opaque->extra_procinfos[basenum].fn_oid))
 	{
 		if (RegProcedureIsValid(index_getprocid(bdesc->bd_index, attno,
 												procnum)))
diff --git a/src/backend/access/brin/brin_inclusion.c b/src/backend/access/brin/brin_inclusion.c
index b86ca5744a3..3a7317a843d 100644
--- a/src/backend/access/brin/brin_inclusion.c
+++ b/src/backend/access/brin/brin_inclusion.c
@@ -560,7 +560,7 @@ inclusion_get_procinfo(BrinDesc *bdesc, uint16 attno, uint16 procnum,
 	if (opaque->extra_proc_missing[basenum])
 		return NULL;
 
-	if (opaque->extra_procinfos[basenum].fn_oid == InvalidOid)
+	if (!OidIsValid(opaque->extra_procinfos[basenum].fn_oid))
 	{
 		if (RegProcedureIsValid(index_getprocid(bdesc->bd_index, attno,
 												procnum)))
@@ -629,7 +629,7 @@ inclusion_get_strategy_procinfo(BrinDesc *bdesc, uint16 attno, Oid subtype,
 		opaque->cached_subtype = subtype;
 	}
 
-	if (opaque->strategy_procinfos[strategynum - 1].fn_oid == InvalidOid)
+	if (!OidIsValid(opaque->strategy_procinfos[strategynum - 1].fn_oid))
 	{
 		Form_pg_attribute attr;
 		HeapTuple	tuple;
diff --git a/src/backend/access/brin/brin_minmax.c b/src/backend/access/brin/brin_minmax.c
index 79c5a0aa185..3744007be23 100644
--- a/src/backend/access/brin/brin_minmax.c
+++ b/src/backend/access/brin/brin_minmax.c
@@ -282,7 +282,7 @@ minmax_get_strategy_procinfo(BrinDesc *bdesc, uint16 attno, Oid subtype,
 		opaque->cached_subtype = subtype;
 	}
 
-	if (opaque->strategy_procinfos[strategynum - 1].fn_oid == InvalidOid)
+	if (!OidIsValid(opaque->strategy_procinfos[strategynum - 1].fn_oid))
 	{
 		Form_pg_attribute attr;
 		HeapTuple	tuple;
diff --git a/src/backend/access/brin/brin_minmax_multi.c b/src/backend/access/brin/brin_minmax_multi.c
index f8a11444d66..e5207e1ee9f 100644
--- a/src/backend/access/brin/brin_minmax_multi.c
+++ b/src/backend/access/brin/brin_minmax_multi.c
@@ -303,7 +303,7 @@ AssertCheckRanges(Ranges *ranges, FmgrInfo *cmpFn, Oid colloid)
 	Assert(ranges->nsorted >= 0);
 	Assert(ranges->nvalues >= ranges->nsorted);
 	Assert(ranges->maxvalues >= 2 * ranges->nranges + ranges->nvalues);
-	Assert(ranges->typid != InvalidOid);
+	Assert(OidIsValid(ranges->typid));
 
 	/*
 	 * First the ranges - there are 2*nranges boundary values, and the values
@@ -2871,7 +2871,7 @@ minmax_multi_get_procinfo(BrinDesc *bdesc, uint16 attno, uint16 procnum)
 	 */
 	opaque = (MinmaxMultiOpaque *) bdesc->bd_info[attno - 1]->oi_opaque;
 
-	if (opaque->extra_procinfos[basenum].fn_oid == InvalidOid)
+	if (!OidIsValid(opaque->extra_procinfos[basenum].fn_oid))
 	{
 		if (RegProcedureIsValid(index_getprocid(bdesc->bd_index, attno,
 												procnum)))
@@ -2920,7 +2920,7 @@ minmax_multi_get_strategy_procinfo(BrinDesc *bdesc, uint16 attno, Oid subtype,
 		opaque->cached_subtype = subtype;
 	}
 
-	if (opaque->strategy_procinfos[strategynum - 1].fn_oid == InvalidOid)
+	if (!OidIsValid(opaque->strategy_procinfos[strategynum - 1].fn_oid))
 	{
 		Form_pg_attribute attr;
 		HeapTuple	tuple;
diff --git a/src/backend/access/common/toast_internals.c b/src/backend/access/common/toast_internals.c
index 81dbd67c725..69ee1267b34 100644
--- a/src/backend/access/common/toast_internals.c
+++ b/src/backend/access/common/toast_internals.c
@@ -260,7 +260,7 @@ toast_save_datum(Relation rel, Datum value,
 				}
 			}
 		}
-		if (toast_pointer.va_valueid == InvalidOid)
+		if (!OidIsValid(toast_pointer.va_valueid))
 		{
 			/*
 			 * new value; must choose an OID that doesn't conflict in either
diff --git a/src/backend/access/gin/gininsert.c b/src/backend/access/gin/gininsert.c
index c2b879b2bf6..512bd403680 100644
--- a/src/backend/access/gin/gininsert.c
+++ b/src/backend/access/gin/gininsert.c
@@ -1302,7 +1302,7 @@ GinBufferInit(Relation index)
 		 * up the index key type's default btree comparator.
 		 */
 		cmpFunc = index_getprocid(index, i + 1, GIN_COMPARE_PROC);
-		if (cmpFunc == InvalidOid)
+		if (!OidIsValid(cmpFunc))
 		{
 			TypeCacheEntry *typentry;
 
diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c
index 49631200a5a..5abca6d750d 100644
--- a/src/backend/access/gin/ginutil.c
+++ b/src/backend/access/gin/ginutil.c
@@ -182,8 +182,8 @@ initGinState(GinState *state, Relation index)
 						   CurrentMemoryContext);
 		}
 
-		if (state->consistentFn[i].fn_oid == InvalidOid &&
-			state->triConsistentFn[i].fn_oid == InvalidOid)
+		if (!OidIsValid(state->consistentFn[i].fn_oid) &&
+			!OidIsValid(state->triConsistentFn[i].fn_oid))
 		{
 			elog(ERROR, "missing GIN support function (%d or %d) for attribute %d of index \"%s\"",
 				 GIN_CONSISTENT_PROC, GIN_TRICONSISTENT_PROC,
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index 75272827837..cfda8b0f2e4 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -677,14 +677,14 @@ gistFetchTuple(GISTSTATE *giststate, Relation r, IndexTuple tuple)
 
 		datum = index_getattr(tuple, i + 1, giststate->leafTupdesc, &isnull[i]);
 
-		if (giststate->fetchFn[i].fn_oid != InvalidOid)
+		if (OidIsValid(giststate->fetchFn[i].fn_oid))
 		{
 			if (!isnull[i])
 				fetchatt[i] = gistFetchAtt(giststate, i, datum, r);
 			else
 				fetchatt[i] = (Datum) 0;
 		}
-		else if (giststate->compressFn[i].fn_oid == InvalidOid)
+		else if (!OidIsValid(giststate->compressFn[i].fn_oid))
 		{
 			/*
 			 * If opclass does not provide compress method that could change
diff --git a/src/backend/access/hash/hashfunc.c b/src/backend/access/hash/hashfunc.c
index ec96348942e..211eca234ff 100644
--- a/src/backend/access/hash/hashfunc.c
+++ b/src/backend/access/hash/hashfunc.c
@@ -271,7 +271,7 @@ hashtext(PG_FUNCTION_ARGS)
 	pg_locale_t mylocale;
 	Datum		result;
 
-	if (!collid)
+	if (!OidIsValid(collid))
 		ereport(ERROR,
 				(errcode(ERRCODE_INDETERMINATE_COLLATION),
 				 errmsg("could not determine which collation to use for string hashing"),
@@ -326,7 +326,7 @@ hashtextextended(PG_FUNCTION_ARGS)
 	pg_locale_t mylocale;
 	Datum		result;
 
-	if (!collid)
+	if (!OidIsValid(collid))
 		ereport(ERROR,
 				(errcode(ERRCODE_INDETERMINATE_COLLATION),
 				 errmsg("could not determine which collation to use for string hashing"),
diff --git a/src/backend/access/hash/hashsearch.c b/src/backend/access/hash/hashsearch.c
index 92c15a65be2..4559978c725 100644
--- a/src/backend/access/hash/hashsearch.c
+++ b/src/backend/access/hash/hashsearch.c
@@ -338,7 +338,7 @@ _hash_first(IndexScanDesc scan, ScanDirection dir)
 	 * opclass input type; this is a hack to simplify life for ScanKeyInit().
 	 */
 	if (cur->sk_subtype == rel->rd_opcintype[0] ||
-		cur->sk_subtype == InvalidOid)
+		!OidIsValid(cur->sk_subtype))
 		hashkey = _hash_datum2hashkey(rel, cur->sk_argument);
 	else
 		hashkey = _hash_datum2hashkey_type(rel, cur->sk_argument,
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 4b0c49f4bb0..c9ebd0e4ced 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -9076,7 +9076,7 @@ log_heap_new_cid(Relation relation, HeapTuple tup)
 	HeapTupleHeader hdr = tup->t_data;
 
 	Assert(ItemPointerIsValid(&tup->t_self));
-	Assert(tup->t_tableOid != InvalidOid);
+	Assert(OidIsValid(tup->t_tableOid));
 
 	xlrec.top_xid = GetTopTransactionId();
 	xlrec.target_locator = relation->rd_locator;
diff --git a/src/backend/access/heap/heapam_visibility.c b/src/backend/access/heap/heapam_visibility.c
index 05f6946fe60..9c8e20a4256 100644
--- a/src/backend/access/heap/heapam_visibility.c
+++ b/src/backend/access/heap/heapam_visibility.c
@@ -172,7 +172,7 @@ HeapTupleSatisfiesSelf(HeapTuple htup, Snapshot snapshot, Buffer buffer)
 	HeapTupleHeader tuple = htup->t_data;
 
 	Assert(ItemPointerIsValid(&htup->t_self));
-	Assert(htup->t_tableOid != InvalidOid);
+	Assert(OidIsValid(htup->t_tableOid));
 
 	if (!HeapTupleHeaderXminCommitted(tuple))
 	{
@@ -365,7 +365,7 @@ HeapTupleSatisfiesToast(HeapTuple htup, Snapshot snapshot,
 	HeapTupleHeader tuple = htup->t_data;
 
 	Assert(ItemPointerIsValid(&htup->t_self));
-	Assert(htup->t_tableOid != InvalidOid);
+	Assert(OidIsValid(htup->t_tableOid));
 
 	if (!HeapTupleHeaderXminCommitted(tuple))
 	{
@@ -461,7 +461,7 @@ HeapTupleSatisfiesUpdate(HeapTuple htup, CommandId curcid,
 	HeapTupleHeader tuple = htup->t_data;
 
 	Assert(ItemPointerIsValid(&htup->t_self));
-	Assert(htup->t_tableOid != InvalidOid);
+	Assert(OidIsValid(htup->t_tableOid));
 
 	if (!HeapTupleHeaderXminCommitted(tuple))
 	{
@@ -746,7 +746,7 @@ HeapTupleSatisfiesDirty(HeapTuple htup, Snapshot snapshot,
 	HeapTupleHeader tuple = htup->t_data;
 
 	Assert(ItemPointerIsValid(&htup->t_self));
-	Assert(htup->t_tableOid != InvalidOid);
+	Assert(OidIsValid(htup->t_tableOid));
 
 	snapshot->xmin = snapshot->xmax = InvalidTransactionId;
 	snapshot->speculativeToken = 0;
@@ -972,7 +972,7 @@ HeapTupleSatisfiesMVCC(HeapTuple htup, Snapshot snapshot,
 	Assert(snapshot->regd_count > 0 || snapshot->active_count > 0);
 
 	Assert(ItemPointerIsValid(&htup->t_self));
-	Assert(htup->t_tableOid != InvalidOid);
+	Assert(OidIsValid(htup->t_tableOid));
 
 	if (!HeapTupleHeaderXminCommitted(tuple))
 	{
@@ -1207,7 +1207,7 @@ HeapTupleSatisfiesVacuumHorizon(HeapTuple htup, Buffer buffer, TransactionId *de
 	HeapTupleHeader tuple = htup->t_data;
 
 	Assert(ItemPointerIsValid(&htup->t_self));
-	Assert(htup->t_tableOid != InvalidOid);
+	Assert(OidIsValid(htup->t_tableOid));
 	Assert(dead_after != NULL);
 
 	*dead_after = InvalidTransactionId;
@@ -1476,7 +1476,7 @@ HeapTupleIsSurelyDead(HeapTuple htup, GlobalVisState *vistest)
 	HeapTupleHeader tuple = htup->t_data;
 
 	Assert(ItemPointerIsValid(&htup->t_self));
-	Assert(htup->t_tableOid != InvalidOid);
+	Assert(OidIsValid(htup->t_tableOid));
 
 	/*
 	 * If the inserting transaction is marked invalid, then it aborted, and
@@ -1601,7 +1601,7 @@ HeapTupleSatisfiesHistoricMVCC(HeapTuple htup, Snapshot snapshot,
 	TransactionId xmax = HeapTupleHeaderGetRawXmax(tuple);
 
 	Assert(ItemPointerIsValid(&htup->t_self));
-	Assert(htup->t_tableOid != InvalidOid);
+	Assert(OidIsValid(htup->t_tableOid));
 
 	/* inserting transaction aborted */
 	if (HeapTupleHeaderXminInvalid(tuple))
diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c
index 0492d92d23b..fb51cde5a6d 100644
--- a/src/backend/access/index/indexam.c
+++ b/src/backend/access/index/indexam.c
@@ -937,7 +937,7 @@ index_getprocinfo(Relation irel,
 	locinfo += procindex;
 
 	/* Initialize the lookup info if first time through */
-	if (locinfo->fn_oid == InvalidOid)
+	if (!OidIsValid(locinfo->fn_oid))
 	{
 		RegProcedure *loc = irel->rd_support;
 		RegProcedure procId;
diff --git a/src/backend/access/nbtree/nbtcompare.c b/src/backend/access/nbtree/nbtcompare.c
index 188c27b4925..0f852833708 100644
--- a/src/backend/access/nbtree/nbtcompare.c
+++ b/src/backend/access/nbtree/nbtcompare.c
@@ -458,7 +458,7 @@ oid_decrement(Relation rel, Datum existing, bool *underflow)
 {
 	Oid			oexisting = DatumGetObjectId(existing);
 
-	if (oexisting == InvalidOid)
+	if (!OidIsValid(oexisting))
 	{
 		/* return value is undefined */
 		*underflow = true;
diff --git a/src/backend/access/nbtree/nbtpreprocesskeys.c b/src/backend/access/nbtree/nbtpreprocesskeys.c
index a871bf62cab..d03d9e4ebc7 100644
--- a/src/backend/access/nbtree/nbtpreprocesskeys.c
+++ b/src/backend/access/nbtree/nbtpreprocesskeys.c
@@ -1013,13 +1013,13 @@ _bt_compare_scankey_args(IndexScanDesc scan, ScanKey op,
 	 * input type; this is a hack to simplify life for ScanKeyInit().
 	 */
 	lefttype = leftarg->sk_subtype;
-	if (lefttype == InvalidOid)
+	if (!OidIsValid(lefttype))
 		lefttype = opcintype;
 	righttype = rightarg->sk_subtype;
-	if (righttype == InvalidOid)
+	if (!OidIsValid(righttype))
 		righttype = opcintype;
 	optype = op->sk_subtype;
-	if (optype == InvalidOid)
+	if (!OidIsValid(optype))
 		optype = opcintype;
 
 	/*
@@ -1150,7 +1150,7 @@ _bt_saoparray_shrink(IndexScanDesc scan, ScanKey arraysk, ScanKey skey,
 	 * means the opclass input type; this is a hack to simplify life for
 	 * ScanKeyInit().
 	 */
-	if (skey->sk_subtype != opcintype && skey->sk_subtype != InvalidOid)
+	if (skey->sk_subtype != opcintype && OidIsValid(skey->sk_subtype))
 	{
 		RegProcedure cmp_proc;
 		Oid			arraysk_elemtype;
@@ -1163,7 +1163,7 @@ _bt_saoparray_shrink(IndexScanDesc scan, ScanKey arraysk, ScanKey skey,
 		 * as its tupdatum/lefthand argument (rhs arg is for array elements).
 		 */
 		arraysk_elemtype = arraysk->sk_subtype;
-		if (arraysk_elemtype == InvalidOid)
+		if (!OidIsValid(arraysk_elemtype))
 			arraysk_elemtype = rel->rd_opcintype[arraysk->sk_attno - 1];
 		cmp_proc = get_opfamily_proc(rel->rd_opfamily[arraysk->sk_attno - 1],
 									 skey->sk_subtype, arraysk_elemtype,
@@ -1421,7 +1421,7 @@ _bt_skiparray_strat_decrement(IndexScanDesc scan, ScanKey arraysk,
 	 * index attribute's input opclass type
 	 */
 	if (high_compare->sk_subtype != opcintype &&
-		high_compare->sk_subtype != InvalidOid)
+		OidIsValid(high_compare->sk_subtype))
 		return;
 
 	/* Decrement, handling underflow by marking the qual unsatisfiable */
@@ -1479,7 +1479,7 @@ _bt_skiparray_strat_increment(IndexScanDesc scan, ScanKey arraysk,
 	 * index attribute's input opclass type
 	 */
 	if (low_compare->sk_subtype != opcintype &&
-		low_compare->sk_subtype != InvalidOid)
+		OidIsValid(low_compare->sk_subtype))
 		return;
 
 	/* Increment, handling overflow by marking the qual unsatisfiable */
@@ -2053,7 +2053,7 @@ _bt_preprocess_array_keys(IndexScanDesc scan, int *new_numberOfKeys)
 		 * ScanKeyInit().
 		 */
 		elemtype = cur->sk_subtype;
-		if (elemtype == InvalidOid)
+		if (!OidIsValid(elemtype))
 			elemtype = rel->rd_opcintype[cur->sk_attno - 1];
 
 		/*
@@ -2266,7 +2266,7 @@ _bt_preprocess_array_keys_final(IndexScanDesc scan, int *keyDataMap)
 				continue;
 
 			elemtype = outkey->sk_subtype;
-			if (elemtype == InvalidOid)
+			if (!OidIsValid(elemtype))
 				elemtype = rel->rd_opcintype[outkey->sk_attno - 1];
 
 			_bt_setup_array_cmp(scan, outkey, elemtype,
diff --git a/src/backend/access/nbtree/nbtsearch.c b/src/backend/access/nbtree/nbtsearch.c
index 0605356ec9f..e23657ba275 100644
--- a/src/backend/access/nbtree/nbtsearch.c
+++ b/src/backend/access/nbtree/nbtsearch.c
@@ -1401,7 +1401,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
 		 * opclass input type; this hack simplifies life for ScanKeyInit().
 		 */
 		if (bkey->sk_subtype == rel->rd_opcintype[i] ||
-			bkey->sk_subtype == InvalidOid)
+			!OidIsValid(bkey->sk_subtype))
 		{
 			FmgrInfo   *procinfo;
 
diff --git a/src/backend/access/table/tableamapi.c b/src/backend/access/table/tableamapi.c
index 476663b66aa..86aeea3f9ab 100644
--- a/src/backend/access/table/tableamapi.c
+++ b/src/backend/access/table/tableamapi.c
@@ -120,7 +120,7 @@ check_default_table_access_method(char **newval, void **extra, GucSource source)
 	 * cannot do the catalog access necessary to verify the method.  Must
 	 * accept the value on faith.
 	 */
-	if (IsTransactionState() && MyDatabaseId != InvalidOid)
+	if (IsTransactionState() && OidIsValid(MyDatabaseId))
 	{
 		if (!OidIsValid(get_table_am_oid(*newval, true)))
 		{
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index fc8638c1b61..60b168e668c 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -566,7 +566,7 @@ DefineAttr(char *name, char *type, int attnum, int nullness)
 		attrtypes[attnum]->attcompression = InvalidCompressionMethod;
 		attrtypes[attnum]->attcollation = TypInfo[typeoid].collation;
 		/* if an array type, assume 1-dimensional attribute */
-		if (TypInfo[typeoid].elem != InvalidOid &&
+		if (OidIsValid(TypInfo[typeoid].elem) &&
 			attrtypes[attnum]->attlen < 0)
 			attrtypes[attnum]->attndims = 1;
 		else
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index cd139bd65a6..e3a0a544cc3 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -2972,7 +2972,8 @@ aclcheck_error_type(AclResult aclerr, Oid typeOid)
 {
 	Oid			element_type = get_element_type(typeOid);
 
-	aclcheck_error(aclerr, OBJECT_TYPE, format_type_be(element_type ? element_type : typeOid));
+	aclcheck_error(aclerr, OBJECT_TYPE,
+				   format_type_be(OidIsValid(element_type) ? element_type : typeOid));
 }
 
 
diff --git a/src/backend/catalog/catalog.c b/src/backend/catalog/catalog.c
index 59caae8f1bc..7a4697a4795 100644
--- a/src/backend/catalog/catalog.c
+++ b/src/backend/catalog/catalog.c
@@ -583,7 +583,7 @@ GetNewRelFileNumber(Oid reltablespace, Relation pg_class, char relpersistence)
 	}
 
 	/* This logic should match RelationInitPhysicalAddr */
-	rlocator.locator.spcOid = reltablespace ? reltablespace : MyDatabaseTableSpace;
+	rlocator.locator.spcOid = OidIsValid(reltablespace) ? reltablespace : MyDatabaseTableSpace;
 	rlocator.locator.dbOid =
 		(rlocator.locator.spcOid == GLOBALTABLESPACE_OID) ?
 		InvalidOid : MyDatabaseId;
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index fd6537567ea..cb16141597c 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -396,7 +396,7 @@ heap_create(const char *relname,
 	 * protected by the existence of a physical file; but for relations with
 	 * no files, add a pg_shdepend entry to account for that.
 	 */
-	if (!create_storage && reltablespace != InvalidOid)
+	if (!create_storage && OidIsValid(reltablespace))
 		recordDependencyOnTablespace(RelationRelationId, relid,
 									 reltablespace);
 
@@ -746,7 +746,7 @@ InsertPgAttributeTuples(Relation pg_attribute_rel,
 		memset(slot[slotCount]->tts_isnull, false,
 			   slot[slotCount]->tts_tupleDescriptor->natts * sizeof(bool));
 
-		if (new_rel_oid != InvalidOid)
+		if (OidIsValid(new_rel_oid))
 			slot[slotCount]->tts_values[Anum_pg_attribute_attrelid - 1] = ObjectIdGetDatum(new_rel_oid);
 		else
 			slot[slotCount]->tts_values[Anum_pg_attribute_attrelid - 1] = ObjectIdGetDatum(attrs->attrelid);
@@ -1024,7 +1024,7 @@ AddNewRelationTuple(Relation pg_class_desc,
 	new_rel_reltup->relispartition = false;
 
 	/* fill rd_att's type ID with something sane even if reltype is zero */
-	new_rel_desc->rd_att->tdtypeid = new_type_oid ? new_type_oid : RECORDOID;
+	new_rel_desc->rd_att->tdtypeid = OidIsValid(new_type_oid) ? new_type_oid : RECORDOID;
 	new_rel_desc->rd_att->tdtypmod = -1;
 
 	/* Now build and insert the tuple */
@@ -1173,7 +1173,7 @@ heap_create_with_catalog(const char *relname,
 	 * by catching it here we can emit a nicer error message.
 	 */
 	existing_relid = get_relname_relid(relname, relnamespace);
-	if (existing_relid != InvalidOid)
+	if (OidIsValid(existing_relid))
 		ereport(ERROR,
 				(errcode(ERRCODE_DUPLICATE_TABLE),
 				 errmsg("relation \"%s\" already exists", relname)));
@@ -1411,7 +1411,7 @@ heap_create_with_catalog(const char *relname,
 	else
 	{
 		/* Caller should not be expecting a type to be created. */
-		Assert(reltypeid == InvalidOid);
+		Assert(!OidIsValid(reltypeid));
 		Assert(typaddress == NULL);
 
 		new_type_oid = InvalidOid;
@@ -1477,7 +1477,7 @@ heap_create_with_catalog(const char *relname,
 		ObjectAddressSet(referenced, NamespaceRelationId, relnamespace);
 		add_exact_object_address(&referenced, addrs);
 
-		if (reloftypeid)
+		if (OidIsValid(reloftypeid))
 		{
 			ObjectAddressSet(referenced, TypeRelationId, reloftypeid);
 			add_exact_object_address(&referenced, addrs);
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 5d9db167e59..120d7ad641c 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -823,7 +823,7 @@ index_create(Relation heapRelation,
 		Oid			collation = collationIds[i];
 		Oid			opclass = opclassIds[i];
 
-		if (collation)
+		if (OidIsValid(collation))
 		{
 			if ((opclass == TEXT_BTREE_PATTERN_OPS_OID ||
 				 opclass == VARCHAR_BTREE_PATTERN_OPS_OID ||
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index d23474da4fb..696d8f5f5ec 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -3891,8 +3891,8 @@ void
 SetTempNamespaceState(Oid tempNamespaceId, Oid tempToastNamespaceId)
 {
 	/* Worker should not have created its own namespaces ... */
-	Assert(myTempNamespace == InvalidOid);
-	Assert(myTempToastNamespace == InvalidOid);
+	Assert(!OidIsValid(myTempNamespace));
+	Assert(!OidIsValid(myTempToastNamespace));
 	Assert(myTempNamespaceSubID == InvalidSubTransactionId);
 
 	/* Assign same namespace OIDs that leader has */
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c75b7131ed7..699ac03b676 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -1129,7 +1129,7 @@ get_object_address(ObjectType objtype, Node *object,
 				/* no default, to let compiler warn about missing case */
 		}
 
-		if (!address.classId)
+		if (!OidIsValid(address.classId))
 			elog(ERROR, "unrecognized object type: %d", (int) objtype);
 
 		/*
@@ -2038,7 +2038,7 @@ get_object_address_defacl(List *object, bool missing_ok)
 	if (schema)
 	{
 		schemaid = get_namespace_oid(schema, true);
-		if (schemaid == InvalidOid)
+		if (!OidIsValid(schemaid))
 			goto not_found;
 	}
 	else
diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index 93d72157a46..995f9d8cf22 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -160,7 +160,7 @@ get_partition_ancestors_worker(Relation inhRel, Oid relid, List **ancestors)
 	 * when the partition is being detached.
 	 */
 	parentOid = get_partition_parent_worker(inhRel, relid, &detach_pending);
-	if (parentOid == InvalidOid || detach_pending)
+	if (!OidIsValid(parentOid) || detach_pending)
 		return;
 
 	*ancestors = lappend_oid(*ancestors, parentOid);
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index a1cb5719a0c..8717659b874 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -213,7 +213,7 @@ AggregateCreate(const char *aggName,
 		else
 		{
 			/* special case with VARIADIC last arg */
-			Assert(variadicArgType != InvalidOid);
+			Assert(OidIsValid(variadicArgType));
 			nargs_transfn = 2;
 		}
 		fnArgs[0] = aggTransType;
diff --git a/src/backend/catalog/pg_inherits.c b/src/backend/catalog/pg_inherits.c
index 929bb53b620..c46ad6f61ed 100644
--- a/src/backend/catalog/pg_inherits.c
+++ b/src/backend/catalog/pg_inherits.c
@@ -415,10 +415,10 @@ typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId)
 
 	/* We need to work with the associated relation OIDs */
 	subclassRelid = typeOrDomainTypeRelid(subclassTypeId);
-	if (subclassRelid == InvalidOid)
+	if (!OidIsValid(subclassRelid))
 		return false;			/* not a complex type or domain over one */
 	superclassRelid = typeidTypeRelid(superclassTypeId);
-	if (superclassRelid == InvalidOid)
+	if (!OidIsValid(superclassRelid))
 		return false;			/* not a complex type */
 
 	/* No point in searching if the superclass has no subclasses */
diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c
index 44d2ccb6788..2263a428afc 100644
--- a/src/backend/catalog/pg_operator.c
+++ b/src/backend/catalog/pg_operator.c
@@ -239,7 +239,7 @@ OperatorShellMake(const char *operatorName,
 	values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
 	values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
 	values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
-	values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? 'b' : 'l');
+	values[Anum_pg_operator_oprkind - 1] = CharGetDatum(OidIsValid(leftTypeId) ? 'b' : 'l');
 	values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(false);
 	values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(false);
 	values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
@@ -462,7 +462,7 @@ OperatorCreate(const char *operatorName,
 	values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
 	values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
 	values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
-	values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? 'b' : 'l');
+	values[Anum_pg_operator_oprkind - 1] = CharGetDatum(OidIsValid(leftTypeId) ? 'b' : 'l');
 	values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(canMerge);
 	values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(canHash);
 	values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
@@ -479,7 +479,7 @@ OperatorCreate(const char *operatorName,
 	/*
 	 * If we are replacing an operator shell, update; else insert
 	 */
-	if (operatorObjectId)
+	if (OidIsValid(operatorObjectId))
 	{
 		isUpdate = true;
 
diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c
index 16e3e5c7457..2f0f1ace7a3 100644
--- a/src/backend/catalog/pg_shdepend.c
+++ b/src/backend/catalog/pg_shdepend.c
@@ -395,7 +395,7 @@ changeDependencyOnTablespace(Oid classId, Oid objectId, Oid newTablespaceId)
 	sdepRel = table_open(SharedDependRelationId, RowExclusiveLock);
 
 	if (newTablespaceId != DEFAULTTABLESPACE_OID &&
-		newTablespaceId != InvalidOid)
+		OidIsValid(newTablespaceId))
 		shdepChangeDep(sdepRel,
 					   classId, objectId, 0,
 					   TableSpaceRelationId, newTablespaceId,
diff --git a/src/backend/catalog/pg_tablespace.c b/src/backend/catalog/pg_tablespace.c
index 6aca24c231e..3b3fade8c42 100644
--- a/src/backend/catalog/pg_tablespace.c
+++ b/src/backend/catalog/pg_tablespace.c
@@ -39,7 +39,7 @@ get_tablespace_location(Oid tablespaceOid)
 	 * "the database's default tablespace".  So, rather than throwing an error
 	 * for zero, we choose to assume that's what is meant.
 	 */
-	if (tablespaceOid == InvalidOid)
+	if (!OidIsValid(tablespaceOid))
 		tablespaceOid = MyDatabaseTableSpace;
 
 	/*
diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c
index 874a8fc89ad..e42bb2a2082 100644
--- a/src/backend/catalog/toasting.c
+++ b/src/backend/catalog/toasting.c
@@ -265,7 +265,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
 										   true,
 										   OIDOldToast,
 										   NULL);
-	Assert(toast_relid != InvalidOid);
+	Assert(OidIsValid(toast_relid));
 
 	/* make the toast relation visible, else table_open will fail */
 	CommandCounterIncrement();
diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c
index 4268adfe787..97376cecf3e 100644
--- a/src/backend/commands/aggregatecmds.c
+++ b/src/backend/commands/aggregatecmds.c
@@ -320,7 +320,7 @@ DefineAggregate(ParseState *pstate,
 		/* Parameter defaults are not currently allowed by the grammar */
 		Assert(parameterDefaults == NIL);
 		/* There shouldn't have been any OUT parameters, either */
-		Assert(requiredResultType == InvalidOid);
+		Assert(!OidIsValid(requiredResultType));
 	}
 
 	/*
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index b55221d44cd..d8990930145 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -776,7 +776,7 @@ make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, Oid NewAccessMethod,
 										  true,
 										  OIDOldHeap,
 										  NULL);
-	Assert(OIDNewHeap != InvalidOid);
+	Assert(OidIsValid(OIDNewHeap));
 
 	ReleaseSysCache(tuple);
 
diff --git a/src/backend/commands/copyto.c b/src/backend/commands/copyto.c
index cef452584e5..24caa59e037 100644
--- a/src/backend/commands/copyto.c
+++ b/src/backend/commands/copyto.c
@@ -844,7 +844,7 @@ BeginCopyTo(ParseState *pstate,
 		 * the relation again, we double-check here to make sure it found the
 		 * same one that we have locked.
 		 */
-		if (queryRelId != InvalidOid)
+		if (OidIsValid(queryRelId))
 		{
 			/*
 			 * Note that with RLS involved there may be multiple relations,
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index f34868da5ab..31ec353139d 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -1623,7 +1623,7 @@ pg_event_trigger_table_rewrite_oid(PG_FUNCTION_ARGS)
 	 * Protect this function from being called out of context
 	 */
 	if (!currentEventTriggerState ||
-		currentEventTriggerState->table_rewrite_oid == InvalidOid)
+		!OidIsValid(currentEventTriggerState->table_rewrite_oid))
 		ereport(ERROR,
 				(errcode(ERRCODE_E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED),
 				 errmsg("%s can only be called in a table_rewrite event trigger function",
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 93ef1ad106f..43a5642fd10 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -3234,7 +3234,7 @@ AlterExtensionNamespace(const char *extensionName, const char *newschema, Oid *o
 		 * If not all the objects had the same old namespace (ignoring any
 		 * that are not in namespaces or are dependent types), complain.
 		 */
-		if (dep_oldNspOid != InvalidOid && dep_oldNspOid != oldNspOid)
+		if (OidIsValid(dep_oldNspOid) && dep_oldNspOid != oldNspOid)
 			ereport(ERROR,
 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 					 errmsg("extension \"%s\" does not support SET SCHEMA",
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 0335e982b31..e6b1aa9b414 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -1160,7 +1160,7 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt)
 			Oid			elt = get_base_element_type(typeid);
 			Oid			transformid;
 
-			typeid = elt ? elt : typeid;
+			typeid = OidIsValid(elt) ? elt : typeid;
 			transformid = get_transform_oid(typeid, languageOid, false);
 			trftypes_list = lappend_oid(trftypes_list, typeid);
 			trfoids_list = lappend_oid(trfoids_list, transformid);
@@ -1188,7 +1188,7 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt)
 	if (stmt->is_procedure)
 	{
 		Assert(!stmt->returnType);
-		prorettype = requiredResultType ? requiredResultType : VOIDOID;
+		prorettype = OidIsValid(requiredResultType) ? requiredResultType : VOIDOID;
 		returnsSet = false;
 	}
 	else if (stmt->returnType)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 5712fac3697..9b23db79be6 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -1049,7 +1049,7 @@ DefineIndex(Oid tableId,
 						else if (exclusion)
 							idx_eqop = indexInfo->ii_ExclusionOps[j];
 
-						if (!idx_eqop)
+						if (!OidIsValid(idx_eqop))
 							ereport(ERROR,
 									errcode(ERRCODE_UNDEFINED_OBJECT),
 									errmsg("could not identify an equality operator for type %s", format_type_be(idx_opcintype)),
@@ -1441,12 +1441,12 @@ DefineIndex(Oid tableId,
 						 * is no such constraint, this index is no good, so
 						 * keep looking.
 						 */
-						if (createdConstraintId != InvalidOid)
+						if (OidIsValid(createdConstraintId))
 						{
 							cldConstrOid =
 								get_relation_idx_constraint_oid(childRelid,
 																cldidxid);
-							if (cldConstrOid == InvalidOid)
+							if (!OidIsValid(cldConstrOid))
 							{
 								index_close(cldidx, lockmode);
 								continue;
@@ -1455,7 +1455,7 @@ DefineIndex(Oid tableId,
 
 						/* Attach index to parent and we're done. */
 						IndexSetParentIndex(cldidx, indexRelationId);
-						if (createdConstraintId != InvalidOid)
+						if (OidIsValid(createdConstraintId))
 							ConstraintSetParentConstraint(cldConstrOid,
 														  createdConstraintId,
 														  childRelid);
@@ -4470,7 +4470,7 @@ IndexSetParentIndex(Relation partitionIdx, Oid parentOid)
 
 	if (!HeapTupleIsValid(tuple))
 	{
-		if (parentOid == InvalidOid)
+		if (!OidIsValid(parentOid))
 		{
 			/*
 			 * No pg_inherits row, and no parent wanted: nothing to do in this
@@ -4488,7 +4488,7 @@ IndexSetParentIndex(Relation partitionIdx, Oid parentOid)
 	{
 		Form_pg_inherits inhForm = (Form_pg_inherits) GETSTRUCT(tuple);
 
-		if (parentOid == InvalidOid)
+		if (!OidIsValid(parentOid))
 		{
 			/*
 			 * There exists a pg_inherits row, which we want to clear; do so.
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 8d671b7a29d..9373b118059 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -211,7 +211,7 @@ DefineSequence(ParseState *pstate, CreateSeqStmt *seq)
 
 	address = DefineRelation(stmt, RELKIND_SEQUENCE, seq->ownerId, NULL, NULL);
 	seqoid = address.objectId;
-	Assert(seqoid != InvalidOid);
+	Assert(OidIsValid(seqoid));
 
 	rel = sequence_open(seqoid, AccessExclusiveLock);
 	tupDesc = RelationGetDescr(rel);
@@ -462,7 +462,7 @@ AlterSequence(ParseState *pstate, AlterSeqStmt *stmt)
 									 stmt->missing_ok ? RVR_MISSING_OK : 0,
 									 RangeVarCallbackOwnsRelation,
 									 NULL);
-	if (relid == InvalidOid)
+	if (!OidIsValid(relid))
 	{
 		ereport(NOTICE,
 				(errmsg("relation \"%s\" does not exist, skipping",
diff --git a/src/backend/commands/statscmds.c b/src/backend/commands/statscmds.c
index 77b1a6e2dc5..4fed5e5e99a 100644
--- a/src/backend/commands/statscmds.c
+++ b/src/backend/commands/statscmds.c
@@ -276,7 +276,7 @@ CreateStatistics(CreateStatsStmt *stmt, bool check_rights)
 
 			/* Disallow data types without a less-than operator */
 			type = lookup_type_cache(attForm->atttypid, TYPECACHE_LT_OPR);
-			if (type->lt_opr == InvalidOid)
+			if (!OidIsValid(type->lt_opr))
 				ereport(ERROR,
 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 						 errmsg("column \"%s\" cannot be used in statistics because its type %s has no default btree operator class",
@@ -305,7 +305,7 @@ CreateStatistics(CreateStatsStmt *stmt, bool check_rights)
 
 			/* Disallow data types without a less-than operator */
 			type = lookup_type_cache(var->vartype, TYPECACHE_LT_OPR);
-			if (type->lt_opr == InvalidOid)
+			if (!OidIsValid(type->lt_opr))
 				ereport(ERROR,
 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 						 errmsg("column \"%s\" cannot be used in statistics because its type %s has no default btree operator class",
@@ -355,7 +355,7 @@ CreateStatistics(CreateStatsStmt *stmt, bool check_rights)
 			{
 				atttype = exprType(expr);
 				type = lookup_type_cache(atttype, TYPECACHE_LT_OPR);
-				if (type->lt_opr == InvalidOid)
+				if (!OidIsValid(type->lt_opr))
 					ereport(ERROR,
 							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 							 errmsg("expression cannot be used in multivariate statistics because its type %s has no default btree operator class",
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 23ebaa3f230..1118a5fc437 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -3692,7 +3692,7 @@ CheckRelationTableSpaceMove(Relation rel, Oid newTableSpaceId)
 	 */
 	oldTableSpaceId = rel->rd_rel->reltablespace;
 	if (newTableSpaceId == oldTableSpaceId ||
-		(newTableSpaceId == MyDatabaseTableSpace && oldTableSpaceId == 0))
+		(newTableSpaceId == MyDatabaseTableSpace && !OidIsValid(oldTableSpaceId)))
 		return false;
 
 	/*
@@ -4050,9 +4050,9 @@ rename_constraint_internal(Oid myrelid,
 	Form_pg_constraint con;
 	ObjectAddress address;
 
-	Assert(!myrelid || !mytypid);
+	Assert(!OidIsValid(myrelid) || !OidIsValid(mytypid));
 
-	if (mytypid)
+	if (OidIsValid(mytypid))
 	{
 		constraintOid = get_domain_constraint_oid(mytypid, oldconname, false);
 	}
@@ -4075,7 +4075,7 @@ rename_constraint_internal(Oid myrelid,
 			 constraintOid);
 	con = (Form_pg_constraint) GETSTRUCT(tuple);
 
-	if (myrelid &&
+	if (OidIsValid(myrelid) &&
 		(con->contype == CONSTRAINT_CHECK ||
 		 con->contype == CONSTRAINT_NOTNULL) &&
 		!con->connoinherit)
@@ -5917,7 +5917,7 @@ ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode,
 			 * Select destination tablespace (same as original unless user
 			 * requested a change)
 			 */
-			if (tab->newTableSpace)
+			if (OidIsValid(tab->newTableSpace))
 				NewTableSpace = tab->newTableSpace;
 			else
 				NewTableSpace = OldHeap->rd_rel->reltablespace;
@@ -6018,7 +6018,7 @@ ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode,
 			 * If we had SET TABLESPACE but no reason to reconstruct tuples,
 			 * just do a block-by-block copy.
 			 */
-			if (tab->newTableSpace)
+			if (OidIsValid(tab->newTableSpace))
 				ATExecSetTableSpace(tab->relid, tab->newTableSpace, lockmode);
 		}
 
@@ -12090,12 +12090,12 @@ GetForeignKeyActionTriggers(Relation trigrel,
 			continue;
 		if (TRIGGER_FOR_DELETE(trgform->tgtype))
 		{
-			Assert(*deleteTriggerOid == InvalidOid);
+			Assert(!OidIsValid(*deleteTriggerOid));
 			*deleteTriggerOid = trgform->oid;
 		}
 		else if (TRIGGER_FOR_UPDATE(trgform->tgtype))
 		{
-			Assert(*updateTriggerOid == InvalidOid);
+			Assert(!OidIsValid(*updateTriggerOid));
 			*updateTriggerOid = trgform->oid;
 		}
 #ifndef USE_ASSERT_CHECKING
@@ -12151,12 +12151,12 @@ GetForeignKeyCheckTriggers(Relation trigrel,
 			continue;
 		if (TRIGGER_FOR_INSERT(trgform->tgtype))
 		{
-			Assert(*insertTriggerOid == InvalidOid);
+			Assert(!OidIsValid(*insertTriggerOid));
 			*insertTriggerOid = trgform->oid;
 		}
 		else if (TRIGGER_FOR_UPDATE(trgform->tgtype))
 		{
-			Assert(*updateTriggerOid == InvalidOid);
+			Assert(!OidIsValid(*updateTriggerOid));
 			*updateTriggerOid = trgform->oid;
 		}
 #ifndef USE_ASSERT_CHECKING
@@ -17112,7 +17112,7 @@ AlterTableMoveAll(AlterTableMoveAllStmt *stmt)
 		ereport(NOTICE,
 				(errcode(ERRCODE_NO_DATA_FOUND),
 				 errmsg("no matching relations in tablespace \"%s\" found",
-						orig_tablespaceoid == InvalidOid ? "(database default)" :
+						!OidIsValid(orig_tablespaceoid) ? "(database default)" :
 						get_tablespace_name(orig_tablespaceoid))));
 
 	/* Everything is locked, loop through and move all of the relations. */
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index df31eace47a..b328411d70a 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -1095,7 +1095,7 @@ check_default_tablespace(char **newval, void **extra, GucSource source)
 	 * cannot do the catalog accesses necessary to verify the name.  Must
 	 * accept the value on faith.
 	 */
-	if (IsTransactionState() && MyDatabaseId != InvalidOid)
+	if (IsTransactionState() && OidIsValid(MyDatabaseId))
 	{
 		if (**newval != '\0' &&
 			!OidIsValid(get_tablespace_oid(*newval, true)))
@@ -1219,7 +1219,7 @@ check_temp_tablespaces(char **newval, void **extra, GucSource source)
 	 * accept the value on faith. Fortunately, there's then also no need to
 	 * pass the data to fd.c.
 	 */
-	if (IsTransactionState() && MyDatabaseId != InvalidOid)
+	if (IsTransactionState() && OidIsValid(MyDatabaseId))
 	{
 		temp_tablespaces_extra *myextra;
 		Oid		   *tblSpcs;
@@ -1249,7 +1249,7 @@ check_temp_tablespaces(char **newval, void **extra, GucSource source)
 			 * nonexistent tablespace, only a NOTICE.  See comments in guc.h.
 			 */
 			curoid = get_tablespace_oid(curname, source <= PGC_S_TEST);
-			if (curoid == InvalidOid)
+			if (!OidIsValid(curoid))
 			{
 				if (source == PGC_S_TEST)
 					ereport(NOTICE,
@@ -1383,7 +1383,7 @@ PrepareTempTablespaces(void)
 
 		/* Else verify that name is a valid tablespace name */
 		curoid = get_tablespace_oid(curname, true);
-		if (curoid == InvalidOid)
+		if (!OidIsValid(curoid))
 		{
 			/* Skip any bad list elements */
 			continue;
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 579ac8d76ae..28dab16d239 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -2335,7 +2335,7 @@ ExecCallTriggerFunc(TriggerData *trigdata,
 	 * We cache fmgr lookup info, to avoid making the lookup again on each
 	 * call.
 	 */
-	if (finfo->fn_oid == InvalidOid)
+	if (!OidIsValid(finfo->fn_oid))
 		fmgr_info(trigdata->tg_trigger->tgfoid, finfo);
 
 	Assert(finfo->fn_oid == trigdata->tg_trigger->tgfoid);
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 5979580139f..341c1b7f574 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -529,28 +529,28 @@ DefineType(ParseState *pstate, List *names, List *parameters)
 	 * findTypeInputFunction et al, where they could be shared by AlterType.
 	 */
 #ifdef NOT_USED
-	if (inputOid && !object_ownercheck(ProcedureRelationId, inputOid, GetUserId()))
+	if (OidIsValid(inputOid) && !object_ownercheck(ProcedureRelationId, inputOid, GetUserId()))
 		aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
 					   NameListToString(inputName));
-	if (outputOid && !object_ownercheck(ProcedureRelationId, outputOid, GetUserId()))
+	if (OidIsValid(outputOid) && !object_ownercheck(ProcedureRelationId, outputOid, GetUserId()))
 		aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
 					   NameListToString(outputName));
-	if (receiveOid && !object_ownercheck(ProcedureRelationId, receiveOid, GetUserId()))
+	if (OidIsValid(receiveOid) && !object_ownercheck(ProcedureRelationId, receiveOid, GetUserId()))
 		aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
 					   NameListToString(receiveName));
-	if (sendOid && !object_ownercheck(ProcedureRelationId, sendOid, GetUserId()))
+	if (OidIsValid(sendOid) && !object_ownercheck(ProcedureRelationId, sendOid, GetUserId()))
 		aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
 					   NameListToString(sendName));
-	if (typmodinOid && !object_ownercheck(ProcedureRelationId, typmodinOid, GetUserId()))
+	if (OidIsValid(typmodinOid) && !object_ownercheck(ProcedureRelationId, typmodinOid, GetUserId()))
 		aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
 					   NameListToString(typmodinName));
-	if (typmodoutOid && !object_ownercheck(ProcedureRelationId, typmodoutOid, GetUserId()))
+	if (OidIsValid(typmodoutOid) && !object_ownercheck(ProcedureRelationId, typmodoutOid, GetUserId()))
 		aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
 					   NameListToString(typmodoutName));
-	if (analyzeOid && !object_ownercheck(ProcedureRelationId, analyzeOid, GetUserId()))
+	if (OidIsValid(analyzeOid) && !object_ownercheck(ProcedureRelationId, analyzeOid, GetUserId()))
 		aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
 					   NameListToString(analyzeName));
-	if (subscriptOid && !object_ownercheck(ProcedureRelationId, subscriptOid, GetUserId()))
+	if (OidIsValid(subscriptOid) && !object_ownercheck(ProcedureRelationId, subscriptOid, GetUserId()))
 		aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
 					   NameListToString(subscriptName));
 #endif
@@ -1592,7 +1592,7 @@ DefineRange(ParseState *pstate, CreateRangeStmt *stmt)
 				   0,			/* Array dimensions of typbasetype */
 				   false,		/* Type NOT NULL */
 				   InvalidOid); /* type's collation (ranges never have one) */
-	Assert(typoid == InvalidOid || typoid == address.objectId);
+	Assert(!OidIsValid(typoid) || typoid == address.objectId);
 	typoid = address.objectId;
 
 	/* Create the multirange that goes with it */
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index e785dd55ce5..27873557c0f 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -2320,7 +2320,7 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
 	 * the toaster always uses hardcoded index access and statistics are
 	 * totally unimportant for toast relations.
 	 */
-	if (toast_relid != InvalidOid)
+	if (OidIsValid(toast_relid))
 	{
 		/*
 		 * Force VACOPT_PROCESS_MAIN so vacuum_rel() processes it.  Likewise,
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index 6f0301555e0..f02c80de0fd 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -245,7 +245,7 @@ DefineVirtualRelation(RangeVar *relation, List *tlist, bool replace,
 		 */
 		address = DefineRelation(createStmt, RELKIND_VIEW, InvalidOid, NULL,
 								 NULL);
-		Assert(address.objectId != InvalidOid);
+		Assert(OidIsValid(address.objectId));
 
 		/* Make the new view relation visible */
 		CommandCounterIncrement();
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index fdc65c2b42b..9b0ee5427aa 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -1495,5 +1495,5 @@ ExecGetResultRelCheckAsUser(ResultRelInfo *relInfo, EState *estate)
 		elog(ERROR, "no RTEPermissionInfo found for result relation with OID %u",
 			 RelationGetRelid(relInfo->ri_RelationDesc));
 
-	return perminfo->checkAsUser ? perminfo->checkAsUser : GetUserId();
+	return OidIsValid(perminfo->checkAsUser) ? perminfo->checkAsUser : GetUserId();
 }
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
index 630d708d2a3..ae4cc1a8f43 100644
--- a/src/backend/executor/functions.c
+++ b/src/backend/executor/functions.c
@@ -286,7 +286,7 @@ prepare_sql_fn_parse_info(HeapTuple procedureTuple,
 			if (IsPolymorphicType(argtype))
 			{
 				argtype = get_call_expr_argtype(call_expr, argnum);
-				if (argtype == InvalidOid)
+				if (!OidIsValid(argtype))
 					ereport(ERROR,
 							(errcode(ERRCODE_DATATYPE_MISMATCH),
 							 errmsg("could not determine actual type of argument declared %s",
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index ede838cd40c..5b11184bd0b 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -1241,12 +1241,12 @@ exprSetCollation(Node *expr, Oid collation)
 		case T_SQLValueFunction:
 			Assert((((SQLValueFunction *) expr)->type == NAMEOID) ?
 				   (collation == C_COLLATION_OID) :
-				   (collation == InvalidOid));
+				   (!OidIsValid(collation)));
 			break;
 		case T_XmlExpr:
 			Assert((((XmlExpr *) expr)->op == IS_XMLSERIALIZE) ?
 				   (collation == DEFAULT_COLLATION_OID) :
-				   (collation == InvalidOid));
+				   (!OidIsValid(collation)));
 			break;
 		case T_JsonValueExpr:
 			exprSetCollation((Node *) ((JsonValueExpr *) expr)->formatted_expr,
@@ -1867,7 +1867,7 @@ fix_opfuncids_walker(Node *node, void *context)
 void
 set_opfuncid(OpExpr *opexpr)
 {
-	if (opexpr->opfuncid == InvalidOid)
+	if (!OidIsValid(opexpr->opfuncid))
 		opexpr->opfuncid = get_opcode(opexpr->opno);
 }
 
@@ -1878,7 +1878,7 @@ set_opfuncid(OpExpr *opexpr)
 void
 set_sa_opfuncid(ScalarArrayOpExpr *opexpr)
 {
-	if (opexpr->opfuncid == InvalidOid)
+	if (!OidIsValid(opexpr->opfuncid))
 		opexpr->opfuncid = get_opcode(opexpr->opno);
 }
 
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index 8335cf5b5c5..6915c2be08a 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -6270,7 +6270,7 @@ set_rel_width(PlannerInfo *root, RelOptInfo *rel)
 			}
 
 			/* Try to get column width from statistics */
-			if (reloid != InvalidOid && var->varattno > 0)
+			if (OidIsValid(reloid) && var->varattno > 0)
 			{
 				item_width = get_attavgwidth(reloid, var->varattno);
 				if (item_width > 0)
@@ -6333,7 +6333,7 @@ set_rel_width(PlannerInfo *root, RelOptInfo *rel)
 	{
 		int64		wholerow_width = MAXALIGN(SizeofHeapTupleHeader);
 
-		if (reloid != InvalidOid)
+		if (OidIsValid(reloid))
 		{
 			/* Real relation, so estimate true tuple width */
 			wholerow_width += get_relation_data_width(reloid,
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index edc6d2ac1d3..62a6642222b 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -3258,7 +3258,7 @@ match_rowcompare_to_indexcol(PlannerInfo *root,
 	{
 		/* indexkey is on right, so commute the operator */
 		expr_op = get_commutator(expr_op);
-		if (expr_op == InvalidOid)
+		if (!OidIsValid(expr_op))
 			return NULL;
 		var_on_left = false;
 	}
@@ -3585,7 +3585,7 @@ expand_indexqual_rowcompare(PlannerInfo *root,
 		{
 			/* indexkey is on right, so commute the operator */
 			expr_op = get_commutator(expr_op);
-			if (expr_op == InvalidOid)
+			if (!OidIsValid(expr_op))
 				break;			/* operator is not usable */
 		}
 		if (bms_is_member(index->rel->relid, pull_varnos(root, constop)))
@@ -3903,7 +3903,7 @@ match_clause_to_ordering_op(IndexOptInfo *index,
 	{
 		/* Might match, but we need a commuted operator */
 		expr_op = get_commutator(expr_op);
-		if (expr_op == InvalidOid)
+		if (!OidIsValid(expr_op))
 			return NULL;
 		commuted = true;
 	}
diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c
index ea5b6415186..0bddd63a613 100644
--- a/src/backend/optimizer/path/joinpath.c
+++ b/src/backend/optimizer/path/joinpath.c
@@ -2155,7 +2155,7 @@ hash_inner_and_outer(PlannerInfo *root,
 			continue;
 
 		if (!restrictinfo->can_join ||
-			restrictinfo->hashjoinoperator == InvalidOid)
+			!OidIsValid(restrictinfo->hashjoinoperator))
 			continue;			/* not hashjoinable */
 
 		/*
diff --git a/src/backend/optimizer/prep/prepqual.c b/src/backend/optimizer/prep/prepqual.c
index 008dce2478c..f8a60f429ee 100644
--- a/src/backend/optimizer/prep/prepqual.c
+++ b/src/backend/optimizer/prep/prepqual.c
@@ -95,7 +95,7 @@ negate_clause(Node *node)
 				OpExpr	   *opexpr = (OpExpr *) node;
 				Oid			negator = get_negator(opexpr->opno);
 
-				if (negator)
+				if (OidIsValid(negator))
 				{
 					OpExpr	   *newopexpr = makeNode(OpExpr);
 
@@ -120,7 +120,7 @@ negate_clause(Node *node)
 				ScalarArrayOpExpr *saopexpr = (ScalarArrayOpExpr *) node;
 				Oid			negator = get_negator(saopexpr->opno);
 
-				if (negator)
+				if (OidIsValid(negator))
 				{
 					ScalarArrayOpExpr *newopexpr = makeNode(ScalarArrayOpExpr);
 
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index a01f781bca8..f244d53d709 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -822,7 +822,7 @@ infer_arbiter_indexes(PlannerInfo *root)
 	 * that already).
 	 */
 	if (onconflict->arbiterElems == NIL &&
-		onconflict->constraint == InvalidOid)
+		!OidIsValid(onconflict->constraint))
 		return NIL;
 
 	/*
@@ -869,11 +869,11 @@ infer_arbiter_indexes(PlannerInfo *root)
 	 * Lookup named constraint's index.  This is not immediately returned
 	 * because some additional sanity checks are required.
 	 */
-	if (onconflict->constraint != InvalidOid)
+	if (OidIsValid(onconflict->constraint))
 	{
 		indexOidFromConstraint = get_constraint_index(onconflict->constraint);
 
-		if (indexOidFromConstraint == InvalidOid)
+		if (!OidIsValid(indexOidFromConstraint))
 			ereport(ERROR,
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 					 errmsg("constraint in ON CONFLICT clause has no associated index")));
@@ -934,7 +934,7 @@ infer_arbiter_indexes(PlannerInfo *root)
 			table_close(relation, NoLock);
 			return results;
 		}
-		else if (indexOidFromConstraint != InvalidOid)
+		else if (OidIsValid(indexOidFromConstraint))
 		{
 			/* No point in further work for index in named constraint case */
 			goto next;
@@ -1003,8 +1003,8 @@ infer_arbiter_indexes(PlannerInfo *root)
 			 * Otherwise, check that element expression appears in cataloged
 			 * index definition.
 			 */
-			if (elem->infercollid != InvalidOid ||
-				elem->inferopclass != InvalidOid ||
+			if (OidIsValid(elem->infercollid) ||
+				OidIsValid(elem->inferopclass) ||
 				list_member(idxExprs, elem->expr))
 				continue;
 
@@ -1088,13 +1088,13 @@ infer_collation_opclass_match(InferenceElem *elem, Relation idxRel,
 	 * If inference specification element lacks collation/opclass, then no
 	 * need to check for exact match.
 	 */
-	if (elem->infercollid == InvalidOid && elem->inferopclass == InvalidOid)
+	if (!OidIsValid(elem->infercollid) && !OidIsValid(elem->inferopclass))
 		return true;
 
 	/*
 	 * Lookup opfamily and input type, for matching indexes
 	 */
-	if (elem->inferopclass)
+	if (OidIsValid(elem->inferopclass))
 	{
 		inferopfamily = get_opclass_family(elem->inferopclass);
 		inferopcinputtype = get_opclass_input_type(elem->inferopclass);
@@ -1110,14 +1110,14 @@ infer_collation_opclass_match(InferenceElem *elem, Relation idxRel,
 		if (attno != 0)
 			nplain++;
 
-		if (elem->inferopclass != InvalidOid &&
+		if (OidIsValid(elem->inferopclass) &&
 			(inferopfamily != opfamily || inferopcinputtype != opcinputtype))
 		{
 			/* Attribute needed to match opclass, but didn't */
 			continue;
 		}
 
-		if (elem->infercollid != InvalidOid &&
+		if (OidIsValid(elem->infercollid) &&
 			elem->infercollid != collation)
 		{
 			/* Attribute needed to match collation, but didn't */
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index ca26f6f61f2..abf44a9beb8 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -3709,7 +3709,7 @@ targetIsInSortList(TargetEntry *tle, Oid sortop, List *sortList)
 		SortGroupClause *scl = (SortGroupClause *) lfirst(l);
 
 		if (scl->tleSortGroupRef == ref &&
-			(sortop == InvalidOid ||
+			(!OidIsValid(sortop) ||
 			 sortop == scl->sortop ||
 			 sortop == get_commutator(scl->sortop)))
 			return true;
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index 78b1e366ad7..d112aaf4464 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -3242,8 +3242,8 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId,
 			Oid			targetElem;
 			Oid			sourceElem;
 
-			if ((targetElem = get_element_type(targetTypeId)) != InvalidOid &&
-				(sourceElem = get_element_type(sourceTypeId)) != InvalidOid)
+			if (OidIsValid((targetElem = get_element_type(targetTypeId))) &&
+				OidIsValid((sourceElem = get_element_type(sourceTypeId))))
 			{
 				CoercionPathType elempathtype;
 				Oid			elemfuncid;
@@ -3383,7 +3383,7 @@ typeIsOfTypedTable(Oid reltypeId, Oid reloftypeId)
 	Oid			relid = typeOrDomainTypeRelid(reltypeId);
 	bool		result = false;
 
-	if (relid)
+	if (OidIsValid(relid))
 	{
 		HeapTuple	tp;
 		Form_pg_class reltup;
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 32d6ae918ca..47b4ba2ccf2 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -1199,7 +1199,7 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
 			array_type = get_array_type(scalar_type);
 		else
 			array_type = InvalidOid;
-		if (array_type != InvalidOid)
+		if (OidIsValid(array_type))
 		{
 			/*
 			 * OK: coerce all the right-hand non-Var inputs to the common type
@@ -2047,7 +2047,7 @@ transformArrayExpr(ParseState *pstate, A_ArrayExpr *a,
 									  element_type,
 									  typmod);
 			/* we certainly have an array here */
-			Assert(array_type == InvalidOid || array_type == exprType(newe));
+			Assert(!OidIsValid(array_type) || array_type == exprType(newe));
 			newa->multidims = true;
 		}
 		else
@@ -2752,7 +2752,7 @@ transformTypeCast(ParseState *pstate, TypeCast *tc)
 		expr = transformExprRecurse(pstate, arg);
 
 	inputType = exprType(expr);
-	if (inputType == InvalidOid)
+	if (!OidIsValid(inputType))
 		return expr;			/* do nothing if NULL input */
 
 	/*
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c
index 7bd7a336fd6..7daebbde586 100644
--- a/src/backend/parser/parse_oper.c
+++ b/src/backend/parser/parse_oper.c
@@ -266,12 +266,12 @@ binary_oper_exact(List *opname, Oid arg1, Oid arg2)
 	bool		was_unknown = false;
 
 	/* Unspecified type for one of the arguments? then use the other */
-	if ((arg1 == UNKNOWNOID) && (arg2 != InvalidOid))
+	if ((arg1 == UNKNOWNOID) && (OidIsValid(arg2)))
 	{
 		arg1 = arg2;
 		was_unknown = true;
 	}
-	else if ((arg2 == UNKNOWNOID) && (arg1 != InvalidOid))
+	else if ((arg2 == UNKNOWNOID) && (OidIsValid(arg1)))
 	{
 		arg2 = arg1;
 		was_unknown = true;
@@ -417,9 +417,9 @@ oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId,
 			 */
 			Oid			inputOids[2];
 
-			if (rtypeId == InvalidOid)
+			if (!OidIsValid(rtypeId))
 				rtypeId = ltypeId;
-			else if (ltypeId == InvalidOid)
+			else if (!OidIsValid(ltypeId))
 				ltypeId = rtypeId;
 			inputOids[0] = ltypeId;
 			inputOids[1] = rtypeId;
@@ -641,7 +641,7 @@ op_error(ParseState *pstate, List *op,
 				(errcode(ERRCODE_UNDEFINED_FUNCTION),
 				 errmsg("operator does not exist: %s",
 						op_signature_string(op, arg1, arg2)),
-				 oper_lookup_failure_details(fgc_flags, (!arg1 || !arg2)),
+				 oper_lookup_failure_details(fgc_flags, (!OidIsValid(arg1) || !OidIsValid(arg2))),
 				 parser_errposition(pstate, location)));
 }
 
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index 905c975d83b..281e01de843 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -775,7 +775,7 @@ transformAssignmentIndirection(ParseState *pstate,
 			baseTypeId = getBaseTypeAndTypmod(targetTypeId, &baseTypeMod);
 
 			typrelid = typeidTypeRelid(baseTypeId);
-			if (!typrelid)
+			if (!OidIsValid(typrelid))
 				ereport(ERROR,
 						(errcode(ERRCODE_DATATYPE_MISMATCH),
 						 errmsg("cannot assign to field \"%s\" of column \"%s\" because its type %s is not a composite type",
diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c
index 7713bdc6af0..c0ddd714db0 100644
--- a/src/backend/parser/parse_type.c
+++ b/src/backend/parser/parse_type.c
@@ -357,7 +357,7 @@ typenameTypeMod(ParseState *pstate, const TypeName *typeName, Type typ)
 
 	typmodin = ((Form_pg_type) GETSTRUCT(typ))->typmodin;
 
-	if (typmodin == InvalidOid)
+	if (!OidIsValid(typmodin))
 		ereport(ERROR,
 				(errcode(ERRCODE_SYNTAX_ERROR),
 				 errmsg("type modifier is not allowed for type \"%s\"",
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index e96b38a59d5..36894527bd4 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -525,7 +525,7 @@ generateSerialExtraStmts(CreateStmtContext *cxt, ColumnDef *column,
 	 * clause, the "redundant options" error will point to their occurrence,
 	 * not our synthetic one.
 	 */
-	if (seqtypid)
+	if (OidIsValid(seqtypid))
 		seqstmt->options = lcons(makeDefElem("as",
 											 (Node *) makeTypeNameFromOid(seqtypid, -1),
 											 -1),
@@ -3746,7 +3746,7 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
 
 					seq_relid = getIdentitySequence(rel, attnum, true);
 
-					if (seq_relid)
+					if (OidIsValid(seq_relid))
 					{
 						AlterSeqStmt *seqstmt;
 
diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
index 239641bfbb6..40f4a4878df 100644
--- a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
+++ b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
@@ -1105,7 +1105,7 @@ libpqrcv_exec(WalReceiverConn *conn, const char *query,
 	WalRcvExecResult *walres = palloc0(sizeof(WalRcvExecResult));
 	char	   *diag_sqlstate;
 
-	if (MyDatabaseId == InvalidOid)
+	if (!OidIsValid(MyDatabaseId))
 		ereport(ERROR,
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 				 errmsg("the query interface requires a database connection")));
diff --git a/src/backend/replication/logical/decode.c b/src/backend/replication/logical/decode.c
index cc03f0706e9..fd3906b2d18 100644
--- a/src/backend/replication/logical/decode.c
+++ b/src/backend/replication/logical/decode.c
@@ -1306,7 +1306,7 @@ DecodeTXNNeedSkip(LogicalDecodingContext *ctx, XLogRecordBuffer *buf,
 				  Oid txn_dbid, RepOriginId origin_id)
 {
 	if (SnapBuildXactNeedsSkip(ctx->snapshot_builder, buf->origptr) ||
-		(txn_dbid != InvalidOid && txn_dbid != ctx->slot->data.database) ||
+		(OidIsValid(txn_dbid) && txn_dbid != ctx->slot->data.database) ||
 		FilterByOrigin(ctx, origin_id))
 		return true;
 
diff --git a/src/backend/replication/logical/logical.c b/src/backend/replication/logical/logical.c
index 866f92cf799..b304f2f8906 100644
--- a/src/backend/replication/logical/logical.c
+++ b/src/backend/replication/logical/logical.c
@@ -122,7 +122,7 @@ CheckLogicalDecodingRequirements(void)
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 				 errmsg("logical decoding requires \"wal_level\" >= \"logical\"")));
 
-	if (MyDatabaseId == InvalidOid)
+	if (!OidIsValid(MyDatabaseId))
 		ereport(ERROR,
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 				 errmsg("logical decoding requires a database connection")));
diff --git a/src/backend/replication/logical/relation.c b/src/backend/replication/logical/relation.c
index 745fd3bab64..9059f7faf73 100644
--- a/src/backend/replication/logical/relation.c
+++ b/src/backend/replication/logical/relation.c
@@ -69,7 +69,7 @@ logicalrep_relmap_invalidate_cb(Datum arg, Oid reloid)
 	if (LogicalRepRelMap == NULL)
 		return;
 
-	if (reloid != InvalidOid)
+	if (OidIsValid(reloid))
 	{
 		HASH_SEQ_STATUS status;
 
@@ -540,7 +540,7 @@ logicalrep_partmap_invalidate_cb(Datum arg, Oid reloid)
 	if (LogicalRepPartMap == NULL)
 		return;
 
-	if (reloid != InvalidOid)
+	if (OidIsValid(reloid))
 	{
 		HASH_SEQ_STATUS status;
 
diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c
index eb6a84554b7..c1c13f43918 100644
--- a/src/backend/replication/logical/reorderbuffer.c
+++ b/src/backend/replication/logical/reorderbuffer.c
@@ -2342,11 +2342,11 @@ ReorderBufferProcessTXN(ReorderBuffer *rb, ReorderBufferTXN *txn,
 					 * whether the table should be logically logged without
 					 * mapping the relfilenumber to the oid.
 					 */
-					if (reloid == InvalidOid &&
+					if (!OidIsValid(reloid) &&
 						change->data.tp.newtuple == NULL &&
 						change->data.tp.oldtuple == NULL)
 						goto change_done;
-					else if (reloid == InvalidOid)
+					else if (!OidIsValid(reloid))
 						elog(ERROR, "could not map filenumber \"%s\" to relation OID",
 							 relpathperm(change->data.tp.rlocator,
 										 MAIN_FORKNUM).str);
diff --git a/src/backend/replication/pgoutput/pgoutput.c b/src/backend/replication/pgoutput/pgoutput.c
index 942e1abdb58..7063dfdab21 100644
--- a/src/backend/replication/pgoutput/pgoutput.c
+++ b/src/backend/replication/pgoutput/pgoutput.c
@@ -2231,7 +2231,7 @@ get_rel_sync_entry(PGOutputData *data, Relation relation)
 															   ancestors,
 															   &level);
 
-					if (ancestor != InvalidOid)
+					if (OidIsValid(ancestor))
 					{
 						ancestor_published = true;
 						if (pub->pubviaroot)
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index 1ec1e997b27..6d8dccb89f1 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -1763,7 +1763,7 @@ DetermineSlotInvalidationCause(uint32 possible_causes, ReplicationSlot *s,
 	{
 		/* invalid DB oid signals a shared relation */
 		if (SlotIsLogical(s) &&
-			(dboid == InvalidOid || dboid == s->data.database))
+			(!OidIsValid(dboid) || dboid == s->data.database))
 		{
 			TransactionId effective_xmin = s->effective_xmin;
 			TransactionId catalog_effective_xmin = s->effective_catalog_xmin;
@@ -2637,7 +2637,7 @@ RestoreSlotFromDisk(const char *name)
 	 * NB: Changing the requirements here also requires adapting
 	 * CheckSlotRequirements() and CheckLogicalDecodingRequirements().
 	 */
-	if (cp.slotdata.database != InvalidOid)
+	if (OidIsValid(cp.slotdata.database))
 	{
 		if (wal_level < WAL_LEVEL_LOGICAL)
 			ereport(FATAL,
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 0478fc9c977..cf25bcfcd22 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -275,17 +275,17 @@ pg_get_replication_slots(PG_FUNCTION_ARGS)
 		i = 0;
 		values[i++] = NameGetDatum(&slot_contents.data.name);
 
-		if (slot_contents.data.database == InvalidOid)
+		if (!OidIsValid(slot_contents.data.database))
 			nulls[i++] = true;
 		else
 			values[i++] = NameGetDatum(&slot_contents.data.plugin);
 
-		if (slot_contents.data.database == InvalidOid)
+		if (!OidIsValid(slot_contents.data.database))
 			values[i++] = CStringGetTextDatum("physical");
 		else
 			values[i++] = CStringGetTextDatum("logical");
 
-		if (slot_contents.data.database == InvalidOid)
+		if (!OidIsValid(slot_contents.data.database))
 			nulls[i++] = true;
 		else
 			values[i++] = ObjectIdGetDatum(slot_contents.data.database);
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index fc8f8559073..8945290e685 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -324,7 +324,7 @@ InitWalSender(void)
 	 * databases.  This allows physical replication clients to send hot
 	 * standby feedback that will delay vacuum cleanup in all databases.
 	 */
-	if (MyDatabaseId == InvalidOid)
+	if (!OidIsValid(MyDatabaseId))
 	{
 		Assert(MyProc->xmin == InvalidTransactionId);
 		LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
@@ -428,7 +428,7 @@ IdentifySystem(void)
 
 	snprintf(xloc, sizeof(xloc), "%X/%08X", LSN_FORMAT_ARGS(logptr));
 
-	if (MyDatabaseId != InvalidOid)
+	if (OidIsValid(MyDatabaseId))
 	{
 		MemoryContext cur = CurrentMemoryContext;
 
@@ -2062,7 +2062,7 @@ exec_replication_command(const char *cmd_string)
 		MemoryContextReset(cmd_context);
 
 		/* XXX this is a pretty random place to make this check */
-		if (MyDatabaseId == InvalidOid)
+		if (!OidIsValid(MyDatabaseId))
 			ereport(ERROR,
 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 					 errmsg("cannot execute SQL commands in WAL sender for physical replication")));
@@ -3067,7 +3067,7 @@ InitWalSenderSlot(void)
 			 * StartLogicalReplication() and CREATE_REPLICATION_SLOT but it
 			 * seems better to set it on one place.
 			 */
-			if (MyDatabaseId == InvalidOid)
+			if (!OidIsValid(MyDatabaseId))
 				walsnd->kind = REPLICATION_KIND_PHYSICAL;
 			else
 				walsnd->kind = REPLICATION_KIND_LOGICAL;
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index adc9e7600e1..80e9077d28f 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -4518,7 +4518,7 @@ build_generation_expression(Relation rel, int attrno)
 	 * expression.
 	 */
 	attcollid = att_tup->attcollation;
-	if (attcollid && attcollid != exprCollation(defexpr))
+	if (OidIsValid(attcollid) && attcollid != exprCollation(defexpr))
 	{
 		CollateExpr *ce = makeNode(CollateExpr);
 
diff --git a/src/backend/statistics/dependencies.c b/src/backend/statistics/dependencies.c
index 6f63b4f3ffb..4b7234fef4e 100644
--- a/src/backend/statistics/dependencies.c
+++ b/src/backend/statistics/dependencies.c
@@ -261,7 +261,7 @@ dependency_degree(StatsBuildData *data, int k, AttrNumber *dependency)
 		TypeCacheEntry *type;
 
 		type = lookup_type_cache(colstat->attrtypid, TYPECACHE_LT_OPR);
-		if (type->lt_opr == InvalidOid) /* shouldn't happen */
+		if (!OidIsValid(type->lt_opr))	/* shouldn't happen */
 			elog(ERROR, "cache lookup failed for ordering operator for type %u",
 				 colstat->attrtypid);
 
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index f59fb821543..e531f74796c 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -359,7 +359,7 @@ build_mss(StatsBuildData *data)
 		TypeCacheEntry *type;
 
 		type = lookup_type_cache(colstat->attrtypid, TYPECACHE_LT_OPR);
-		if (type->lt_opr == InvalidOid) /* shouldn't happen */
+		if (!OidIsValid(type->lt_opr))	/* shouldn't happen */
 			elog(ERROR, "cache lookup failed for ordering operator for type %u",
 				 colstat->attrtypid);
 
diff --git a/src/backend/statistics/mvdistinct.c b/src/backend/statistics/mvdistinct.c
index fe452f53ae4..dc2b801b30e 100644
--- a/src/backend/statistics/mvdistinct.c
+++ b/src/backend/statistics/mvdistinct.c
@@ -387,7 +387,7 @@ ndistinct_for_combination(double totalrows, StatsBuildData *data,
 		collid = colstat->attrcollid;
 
 		type = lookup_type_cache(typid, TYPECACHE_LT_OPR);
-		if (type->lt_opr == InvalidOid) /* shouldn't happen */
+		if (!OidIsValid(type->lt_opr))	/* shouldn't happen */
 			elog(ERROR, "cache lookup failed for ordering operator for type %u",
 				 typid);
 
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 327ddb7adc8..a7355ed57a7 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -3449,7 +3449,7 @@ BufferSync(int flags)
 		 * Grow array of per-tablespace status structs, every time a new
 		 * tablespace is found.
 		 */
-		if (last_tsid == InvalidOid || last_tsid != cur_tsid)
+		if (!OidIsValid(last_tsid) || last_tsid != cur_tsid)
 		{
 			Size		sz;
 
diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c
index e9eaaf9c829..cca2be29899 100644
--- a/src/backend/storage/file/fd.c
+++ b/src/backend/storage/file/fd.c
@@ -1758,7 +1758,7 @@ OpenTemporaryFile(bool interXact)
 	 * here, but just in case it isn't, fall back to pg_default tablespace.
 	 */
 	if (file <= 0)
-		file = OpenTemporaryFileInTablespace(MyDatabaseTableSpace ?
+		file = OpenTemporaryFileInTablespace(OidIsValid(MyDatabaseTableSpace) ?
 											 MyDatabaseTableSpace :
 											 DEFAULTTABLESPACE_OID,
 											 true);
@@ -1784,7 +1784,7 @@ TempTablespacePath(char *path, Oid tablespace)
 	 *
 	 * If someone tries to specify pg_global, use pg_default instead.
 	 */
-	if (tablespace == InvalidOid ||
+	if (!OidIsValid(tablespace) ||
 		tablespace == DEFAULTTABLESPACE_OID ||
 		tablespace == GLOBALTABLESPACE_OID)
 		snprintf(path, MAXPGPATH, "base/%s", PG_TEMP_FILES_DIR);
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index 200f72c6e25..7d81ac78264 100644
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -1803,7 +1803,7 @@ ComputeXidHorizons(ComputeXidHorizonsResult *h)
 		 * machinery.
 		 */
 		if (proc->databaseId == MyDatabaseId ||
-			MyDatabaseId == InvalidOid ||
+			!OidIsValid(MyDatabaseId) ||
 			(statusFlags & PROC_AFFECTS_ALL_HORIZONS) ||
 			in_recovery)
 		{
@@ -3631,7 +3631,7 @@ CancelDBBackends(Oid databaseid, ProcSignalReason sigmode, bool conflictPending)
 		int			pgprocno = arrayP->pgprocnos[index];
 		PGPROC	   *proc = &allProcs[pgprocno];
 
-		if (databaseid == InvalidOid || proc->databaseId == databaseid)
+		if (!OidIsValid(databaseid) || proc->databaseId == databaseid)
 		{
 			VirtualTransactionId procvxid;
 			pid_t		pid;
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 4cc7f645c31..de5829fc368 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -268,7 +268,7 @@ int			FastPathLockGroupsPerBackend = 0;
 	((locktag)->locktag_lockmethodid == DEFAULT_LOCKMETHOD && \
 	(locktag)->locktag_type == LOCKTAG_RELATION && \
 	(locktag)->locktag_field1 == MyDatabaseId && \
-	MyDatabaseId != InvalidOid && \
+	OidIsValid(MyDatabaseId) && \
 	(mode) < ShareUpdateExclusiveLock)
 #define ConflictsWithRelationFastPath(locktag, mode) \
 	((locktag)->locktag_lockmethodid == DEFAULT_LOCKMETHOD && \
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index bb807d8c9cd..c983f7fce52 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -2971,7 +2971,7 @@ DropAllPredicateLocksFromTable(Relation relation, bool transfer)
 		isIndex = true;
 		heapId = relation->rd_index->indrelid;
 	}
-	Assert(heapId != InvalidOid);
+	Assert(OidIsValid(heapId));
 	Assert(transfer || !isIndex);	/* index OID only makes sense with
 									 * transfer */
 
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 7dd75a490aa..19e00b1d259 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -733,7 +733,7 @@ pg_analyze_and_rewrite_varparams(RawStmt *parsetree,
 	{
 		Oid			ptype = (*paramTypes)[i];
 
-		if (ptype == InvalidOid || ptype == UNKNOWNOID)
+		if (!OidIsValid(ptype) || ptype == UNKNOWNOID)
 			ereport(ERROR,
 					(errcode(ERRCODE_INDETERMINATE_DATATYPE),
 					 errmsg("could not determine data type of parameter $%d",
diff --git a/src/backend/tsearch/ts_parse.c b/src/backend/tsearch/ts_parse.c
index cba421892bf..540c3f70703 100644
--- a/src/backend/tsearch/ts_parse.c
+++ b/src/backend/tsearch/ts_parse.c
@@ -177,7 +177,7 @@ LexizeExec(LexizeData *ld, ParsedLex **correspondLexem)
 	TSDictionaryCacheEntry *dict;
 	TSLexeme   *res;
 
-	if (ld->curDictId == InvalidOid)
+	if (!OidIsValid(ld->curDictId))
 	{
 		/*
 		 * usual mode: dictionary wants only one word, but we should keep in
diff --git a/src/backend/utils/activity/pgstat.c b/src/backend/utils/activity/pgstat.c
index 7ef06150df7..b16ba5aebaa 100644
--- a/src/backend/utils/activity/pgstat.c
+++ b/src/backend/utils/activity/pgstat.c
@@ -1156,7 +1156,7 @@ pgstat_build_snapshot(void)
 		 * relations).
 		 */
 		if (p->key.dboid != MyDatabaseId &&
-			p->key.dboid != InvalidOid &&
+			OidIsValid(p->key.dboid) &&
 			!kind_info->accessed_across_databases)
 			continue;
 
diff --git a/src/backend/utils/adt/array_selfuncs.c b/src/backend/utils/adt/array_selfuncs.c
index 4dab35b0057..fe72f25a20d 100644
--- a/src/backend/utils/adt/array_selfuncs.c
+++ b/src/backend/utils/adt/array_selfuncs.c
@@ -296,7 +296,7 @@ arraycontsel(PG_FUNCTION_ARGS)
 	 * we'd rather just return a default estimate.)
 	 */
 	element_typeid = get_base_element_type(((Const *) other)->consttype);
-	if (element_typeid != InvalidOid &&
+	if (OidIsValid(element_typeid) &&
 		element_typeid == get_base_element_type(vardata.vartype))
 	{
 		selec = calc_arraycontsel(&vardata, ((Const *) other)->constvalue,
diff --git a/src/backend/utils/adt/array_userfuncs.c b/src/backend/utils/adt/array_userfuncs.c
index 8eb342e3382..0f655af6e0f 100644
--- a/src/backend/utils/adt/array_userfuncs.c
+++ b/src/backend/utils/adt/array_userfuncs.c
@@ -559,7 +559,7 @@ array_agg_transfn(PG_FUNCTION_ARGS)
 	ArrayBuildState *state;
 	Datum		elem;
 
-	if (arg1_typeid == InvalidOid)
+	if (!OidIsValid(arg1_typeid))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("could not determine input data type")));
@@ -936,7 +936,7 @@ array_agg_array_transfn(PG_FUNCTION_ARGS)
 	MemoryContext aggcontext;
 	ArrayBuildStateArr *state;
 
-	if (arg1_typeid == InvalidOid)
+	if (!OidIsValid(arg1_typeid))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("could not determine input data type")));
diff --git a/src/backend/utils/adt/enum.c b/src/backend/utils/adt/enum.c
index fcc6981632b..4c2a456c12a 100644
--- a/src/backend/utils/adt/enum.c
+++ b/src/backend/utils/adt/enum.c
@@ -445,7 +445,7 @@ enum_first(PG_FUNCTION_ARGS)
 	 * examined at all; in particular it might be NULL.
 	 */
 	enumtypoid = get_fn_expr_argtype(fcinfo->flinfo, 0);
-	if (enumtypoid == InvalidOid)
+	if (!OidIsValid(enumtypoid))
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("could not determine actual enum type")));
@@ -474,7 +474,7 @@ enum_last(PG_FUNCTION_ARGS)
 	 * examined at all; in particular it might be NULL.
 	 */
 	enumtypoid = get_fn_expr_argtype(fcinfo->flinfo, 0);
-	if (enumtypoid == InvalidOid)
+	if (!OidIsValid(enumtypoid))
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("could not determine actual enum type")));
@@ -514,7 +514,7 @@ enum_range_bounds(PG_FUNCTION_ARGS)
 	 * both are of the same type.
 	 */
 	enumtypoid = get_fn_expr_argtype(fcinfo->flinfo, 0);
-	if (enumtypoid == InvalidOid)
+	if (!OidIsValid(enumtypoid))
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("could not determine actual enum type")));
@@ -534,7 +534,7 @@ enum_range_all(PG_FUNCTION_ARGS)
 	 * examined at all; in particular it might be NULL.
 	 */
 	enumtypoid = get_fn_expr_argtype(fcinfo->flinfo, 0);
-	if (enumtypoid == InvalidOid)
+	if (!OidIsValid(enumtypoid))
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("could not determine actual enum type")));
diff --git a/src/backend/utils/adt/format_type.c b/src/backend/utils/adt/format_type.c
index 9948c26e76c..4b7f7cdae3a 100644
--- a/src/backend/utils/adt/format_type.c
+++ b/src/backend/utils/adt/format_type.c
@@ -118,7 +118,7 @@ format_type_extended(Oid type_oid, int32 typemod, bits16 flags)
 	char	   *buf;
 	bool		with_typemod;
 
-	if (type_oid == InvalidOid)
+	if (!OidIsValid(type_oid))
 	{
 		if ((flags & FORMAT_TYPE_INVALID_AS_NULL) != 0)
 			return NULL;
@@ -375,7 +375,7 @@ printTypmod(const char *typname, int32 typmod, Oid typmodout)
 	/* Shouldn't be called if typmod is -1 */
 	Assert(typmod >= 0);
 
-	if (typmodout == InvalidOid)
+	if (!OidIsValid(typmodout))
 	{
 		/* Default behavior: just print the integer typmod with parens */
 		res = psprintf("%s(%d)", typname, (int) typmod);
diff --git a/src/backend/utils/adt/json.c b/src/backend/utils/adt/json.c
index 06dd62f0008..6316b7a4fab 100644
--- a/src/backend/utils/adt/json.c
+++ b/src/backend/utils/adt/json.c
@@ -606,7 +606,7 @@ add_json(Datum val, bool is_null, StringInfo result,
 	JsonTypeCategory tcategory;
 	Oid			outfuncoid;
 
-	if (val_type == InvalidOid)
+	if (!OidIsValid(val_type))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("could not determine input data type")));
@@ -744,7 +744,7 @@ to_json(PG_FUNCTION_ARGS)
 	JsonTypeCategory tcategory;
 	Oid			outfuncoid;
 
-	if (val_type == InvalidOid)
+	if (!OidIsValid(val_type))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("could not determine input data type")));
@@ -795,7 +795,7 @@ json_agg_transfn_worker(FunctionCallInfo fcinfo, bool absent_on_null)
 	{
 		Oid			arg_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
 
-		if (arg_type == InvalidOid)
+		if (!OidIsValid(arg_type))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 					 errmsg("could not determine input data type")));
@@ -1039,7 +1039,7 @@ json_object_agg_transfn_worker(FunctionCallInfo fcinfo,
 
 		arg_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
 
-		if (arg_type == InvalidOid)
+		if (!OidIsValid(arg_type))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 					 errmsg("could not determine data type for argument %d", 1)));
@@ -1049,7 +1049,7 @@ json_object_agg_transfn_worker(FunctionCallInfo fcinfo,
 
 		arg_type = get_fn_expr_argtype(fcinfo->flinfo, 2);
 
-		if (arg_type == InvalidOid)
+		if (!OidIsValid(arg_type))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 					 errmsg("could not determine data type for argument %d", 2)));
diff --git a/src/backend/utils/adt/jsonb.c b/src/backend/utils/adt/jsonb.c
index 9399cdb491a..a9e21aa5008 100644
--- a/src/backend/utils/adt/jsonb.c
+++ b/src/backend/utils/adt/jsonb.c
@@ -1020,7 +1020,7 @@ add_jsonb(Datum val, bool is_null, JsonbInState *result,
 	JsonTypeCategory tcategory;
 	Oid			outfuncoid;
 
-	if (val_type == InvalidOid)
+	if (!OidIsValid(val_type))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("could not determine input data type")));
@@ -1093,7 +1093,7 @@ to_jsonb(PG_FUNCTION_ARGS)
 	JsonTypeCategory tcategory;
 	Oid			outfuncoid;
 
-	if (val_type == InvalidOid)
+	if (!OidIsValid(val_type))
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("could not determine input data type")));
@@ -1525,7 +1525,7 @@ jsonb_agg_transfn_worker(FunctionCallInfo fcinfo, bool absent_on_null)
 	{
 		Oid			arg_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
 
-		if (arg_type == InvalidOid)
+		if (!OidIsValid(arg_type))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 					 errmsg("could not determine input data type")));
@@ -1713,7 +1713,7 @@ jsonb_object_agg_transfn_worker(FunctionCallInfo fcinfo,
 
 		arg_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
 
-		if (arg_type == InvalidOid)
+		if (!OidIsValid(arg_type))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 					 errmsg("could not determine input data type")));
@@ -1723,7 +1723,7 @@ jsonb_object_agg_transfn_worker(FunctionCallInfo fcinfo,
 
 		arg_type = get_fn_expr_argtype(fcinfo->flinfo, 2);
 
-		if (arg_type == InvalidOid)
+		if (!OidIsValid(arg_type))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 					 errmsg("could not determine input data type")));
diff --git a/src/backend/utils/adt/like_support.c b/src/backend/utils/adt/like_support.c
index 999f23f86d5..5dbb2f57b4b 100644
--- a/src/backend/utils/adt/like_support.c
+++ b/src/backend/utils/adt/like_support.c
@@ -405,7 +405,7 @@ match_pattern_prefix(Node *leftop,
 	 *
 	 * expr_coll is not set for a non-collation-aware data type such as bytea.
 	 */
-	if (expr_coll && !get_collation_isdeterministic(expr_coll))
+	if (OidIsValid(expr_coll) && !get_collation_isdeterministic(expr_coll))
 		return NIL;
 
 	/*
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index a365c432d34..8d84efc42c3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -284,7 +284,7 @@ pg_tablespace_databases(PG_FUNCTION_ARGS)
 		bool		nulls[1];
 
 		/* this test skips . and .., but is awfully weak */
-		if (!datOid)
+		if (!OidIsValid(datOid))
 			continue;
 
 		/* if database subdir is empty, don't report tablespace as used */
@@ -593,7 +593,7 @@ pg_collation_for(PG_FUNCTION_ARGS)
 	Oid			collid;
 
 	typeid = get_fn_expr_argtype(fcinfo->flinfo, 0);
-	if (!typeid)
+	if (!OidIsValid(typeid))
 		PG_RETURN_NULL();
 	if (!type_is_collatable(typeid) && typeid != UNKNOWNOID)
 		ereport(ERROR,
@@ -602,7 +602,7 @@ pg_collation_for(PG_FUNCTION_ARGS)
 						format_type_be(typeid))));
 
 	collid = PG_GET_COLLATION();
-	if (!collid)
+	if (!OidIsValid(collid))
 		PG_RETURN_NULL();
 	PG_RETURN_TEXT_P(cstring_to_text(generate_collation_name(collid)));
 }
@@ -761,7 +761,7 @@ pg_input_is_valid_common(FunctionCallInfo fcinfo,
 	 * If the typname argument is constant, we only need to parse it the first
 	 * time through.
 	 */
-	if (my_extra->typoid == InvalidOid || !my_extra->typname_constant)
+	if (!OidIsValid(my_extra->typoid) || !my_extra->typname_constant)
 	{
 		char	   *typnamestr = text_to_cstring(typname);
 		Oid			typoid;
diff --git a/src/backend/utils/adt/multirangetypes_selfuncs.c b/src/backend/utils/adt/multirangetypes_selfuncs.c
index 21f0205d803..d5cd6adc2bc 100644
--- a/src/backend/utils/adt/multirangetypes_selfuncs.c
+++ b/src/backend/utils/adt/multirangetypes_selfuncs.c
@@ -183,7 +183,7 @@ multirangesel(PG_FUNCTION_ARGS)
 	{
 		/* we have other Op var, commute to make var Op other */
 		operator = get_commutator(operator);
-		if (!operator)
+		if (!OidIsValid(operator))
 		{
 			/* Use default selectivity (should we raise an error instead?) */
 			ReleaseVariableStats(vardata);
diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c
index 3cb0ab6829a..f0962aff0d1 100644
--- a/src/backend/utils/adt/network.c
+++ b/src/backend/utils/adt/network.c
@@ -1064,7 +1064,7 @@ match_network_subset(Node *leftop,
 	 * operator disallows equality.
 	 */
 	opr1oid = get_opfamily_member_for_cmptype(opfamily, datatype, datatype, is_eq ? COMPARE_GE : COMPARE_GT);
-	if (opr1oid == InvalidOid)
+	if (!OidIsValid(opr1oid))
 		return NIL;
 
 	opr1right = network_scan_first(rightopval);
@@ -1081,7 +1081,7 @@ match_network_subset(Node *leftop,
 	/* create clause "key <= network_scan_last( rightopval )" */
 
 	opr2oid = get_opfamily_member_for_cmptype(opfamily, datatype, datatype, COMPARE_LE);
-	if (opr2oid == InvalidOid)
+	if (!OidIsValid(opr2oid))
 		return NIL;
 
 	opr2right = network_scan_last(rightopval);
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 1521d6e2ab4..5b8727349b0 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -380,14 +380,14 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 			continue;
 
 		/* Values available to all callers */
-		if (beentry->st_databaseid != InvalidOid)
+		if (OidIsValid(beentry->st_databaseid))
 			values[0] = ObjectIdGetDatum(beentry->st_databaseid);
 		else
 			nulls[0] = true;
 
 		values[1] = Int32GetDatum(beentry->st_procpid);
 
-		if (beentry->st_userid != InvalidOid)
+		if (OidIsValid(beentry->st_userid))
 			values[2] = ObjectIdGetDatum(beentry->st_userid);
 		else
 			nulls[2] = true;
diff --git a/src/backend/utils/adt/rangetypes_selfuncs.c b/src/backend/utils/adt/rangetypes_selfuncs.c
index d85252cafb2..f112aac5b26 100644
--- a/src/backend/utils/adt/rangetypes_selfuncs.c
+++ b/src/backend/utils/adt/rangetypes_selfuncs.c
@@ -153,7 +153,7 @@ rangesel(PG_FUNCTION_ARGS)
 	{
 		/* we have other Op var, commute to make var Op other */
 		operator = get_commutator(operator);
-		if (!operator)
+		if (!OidIsValid(operator))
 		{
 			/* Use default selectivity (should we raise an error instead?) */
 			ReleaseVariableStats(vardata);
diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c
index 7ce61efd947..22b0319abdf 100644
--- a/src/backend/utils/adt/regproc.c
+++ b/src/backend/utils/adt/regproc.c
@@ -555,7 +555,7 @@ regoperout(PG_FUNCTION_ARGS)
 	char	   *result;
 	HeapTuple	opertup;
 
-	if (oprid == InvalidOid)
+	if (!OidIsValid(oprid))
 	{
 		result = pstrdup("0");
 		PG_RETURN_CSTRING(result);
@@ -849,7 +849,7 @@ regoperatorout(PG_FUNCTION_ARGS)
 	Oid			oprid = PG_GETARG_OID(0);
 	char	   *result;
 
-	if (oprid == InvalidOid)
+	if (!OidIsValid(oprid))
 		result = pstrdup("0");
 	else
 		result = format_operator(oprid);
@@ -954,7 +954,7 @@ regclassout(PG_FUNCTION_ARGS)
 	char	   *result;
 	HeapTuple	classtup;
 
-	if (classid == InvalidOid)
+	if (!OidIsValid(classid))
 	{
 		result = pstrdup("-");
 		PG_RETURN_CSTRING(result);
@@ -1097,7 +1097,7 @@ regcollationout(PG_FUNCTION_ARGS)
 	char	   *result;
 	HeapTuple	collationtup;
 
-	if (collationid == InvalidOid)
+	if (!OidIsValid(collationid))
 	{
 		result = pstrdup("-");
 		PG_RETURN_CSTRING(result);
@@ -1258,7 +1258,7 @@ regtypeout(PG_FUNCTION_ARGS)
 	char	   *result;
 	HeapTuple	typetup;
 
-	if (typid == InvalidOid)
+	if (!OidIsValid(typid))
 	{
 		result = pstrdup("-");
 		PG_RETURN_CSTRING(result);
@@ -1370,7 +1370,7 @@ regconfigout(PG_FUNCTION_ARGS)
 	char	   *result;
 	HeapTuple	cfgtup;
 
-	if (cfgid == InvalidOid)
+	if (!OidIsValid(cfgid))
 	{
 		result = pstrdup("-");
 		PG_RETURN_CSTRING(result);
@@ -1480,7 +1480,7 @@ regdictionaryout(PG_FUNCTION_ARGS)
 	char	   *result;
 	HeapTuple	dicttup;
 
-	if (dictid == InvalidOid)
+	if (!OidIsValid(dictid))
 	{
 		result = pstrdup("-");
 		PG_RETURN_CSTRING(result);
@@ -1611,7 +1611,7 @@ regroleout(PG_FUNCTION_ARGS)
 	Oid			roleoid = PG_GETARG_OID(0);
 	char	   *result;
 
-	if (roleoid == InvalidOid)
+	if (!OidIsValid(roleoid))
 	{
 		result = pstrdup("-");
 		PG_RETURN_CSTRING(result);
@@ -1728,7 +1728,7 @@ regnamespaceout(PG_FUNCTION_ARGS)
 	Oid			nspid = PG_GETARG_OID(0);
 	char	   *result;
 
-	if (nspid == InvalidOid)
+	if (!OidIsValid(nspid))
 	{
 		result = pstrdup("-");
 		PG_RETURN_CSTRING(result);
@@ -1845,7 +1845,7 @@ regdatabaseout(PG_FUNCTION_ARGS)
 	Oid			dboid = PG_GETARG_OID(0);
 	char	   *result;
 
-	if (dboid == InvalidOid)
+	if (!OidIsValid(dboid))
 	{
 		result = pstrdup("-");
 		PG_RETURN_CSTRING(result);
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 556ab057e5a..1e4f57bf245 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -10425,12 +10425,12 @@ get_rule_expr(Node *node, deparse_context *context,
 
 				context->varprefix = save_varprefix;
 
-				if (iexpr->infercollid)
+				if (OidIsValid(iexpr->infercollid))
 					appendStringInfo(buf, " COLLATE %s",
 									 generate_collation_name(iexpr->infercollid));
 
 				/* Add the operator class name, if not default */
-				if (iexpr->inferopclass)
+				if (OidIsValid(iexpr->inferopclass))
 				{
 					Oid			inferopclass = iexpr->inferopclass;
 					Oid			inferopcinputtype = get_opclass_input_type(iexpr->inferopclass);
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 911376f79e8..6ea9b19fd27 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -1450,7 +1450,7 @@ scalarineqsel_wrapper(PG_FUNCTION_ARGS, bool isgt, bool iseq)
 	if (!varonleft)
 	{
 		operator = get_commutator(operator);
-		if (!operator)
+		if (!OidIsValid(operator))
 		{
 			/* Use default selectivity (should we raise an error instead?) */
 			ReleaseVariableStats(vardata);
@@ -2886,7 +2886,7 @@ neqjoinsel(PG_FUNCTION_ARGS)
 		 */
 		Oid			eqop = get_negator(operator);
 
-		if (eqop)
+		if (OidIsValid(eqop))
 		{
 			result =
 				DatumGetFloat8(DirectFunctionCall5Coll(eqjoinsel,
@@ -4338,7 +4338,7 @@ estimate_multivariate_ndistinct(PlannerInfo *root, RelOptInfo *rel,
 	}
 
 	/* No match? */
-	if (statOid == InvalidOid)
+	if (!OidIsValid(statOid))
 		return false;
 
 	Assert(nmatches_vars + nmatches_exprs > 1);
@@ -6116,7 +6116,7 @@ examine_indexcol_variable(PlannerInfo *root, IndexOptInfo *index,
 
 		Assert(rte->rtekind == RTE_RELATION);
 		relid = rte->relid;
-		Assert(relid != InvalidOid);
+		Assert(OidIsValid(relid));
 		colnum = index->indexkeys[indexcol];
 		vardata->rel = index->rel;
 
diff --git a/src/backend/utils/adt/varchar.c b/src/backend/utils/adt/varchar.c
index 3f40c9da1a0..6e3f4e6df7f 100644
--- a/src/backend/utils/adt/varchar.c
+++ b/src/backend/utils/adt/varchar.c
@@ -994,7 +994,7 @@ hashbpchar(PG_FUNCTION_ARGS)
 	pg_locale_t mylocale;
 	Datum		result;
 
-	if (!collid)
+	if (!OidIsValid(collid))
 		ereport(ERROR,
 				(errcode(ERRCODE_INDETERMINATE_COLLATION),
 				 errmsg("could not determine which collation to use for string hashing"),
@@ -1050,7 +1050,7 @@ hashbpcharextended(PG_FUNCTION_ARGS)
 	pg_locale_t mylocale;
 	Datum		result;
 
-	if (!collid)
+	if (!OidIsValid(collid))
 		ereport(ERROR,
 				(errcode(ERRCODE_INDETERMINATE_COLLATION),
 				 errmsg("could not determine which collation to use for string hashing"),
diff --git a/src/backend/utils/cache/inval.c b/src/backend/utils/cache/inval.c
index 02505c88b8e..25893fc0d78 100644
--- a/src/backend/utils/cache/inval.c
+++ b/src/backend/utils/cache/inval.c
@@ -647,7 +647,7 @@ RegisterRelcacheInvalidation(InvalidationInfo *info, Oid dbId, Oid relId)
 	 * invalidations for a specific database always invalidate the shared file
 	 * as well.  Also zap when we are invalidating whole relcache.
 	 */
-	if (relId == InvalidOid || RelationIdIsInInitFile(relId))
+	if (!OidIsValid(relId) || RelationIdIsInInitFile(relId))
 		info->RelcacheInitFileInval = true;
 }
 
@@ -824,7 +824,7 @@ LocalExecuteInvalidationMessage(SharedInvalidationMessage *msg)
 {
 	if (msg->id >= 0)
 	{
-		if (msg->cc.dbId == MyDatabaseId || msg->cc.dbId == InvalidOid)
+		if (msg->cc.dbId == MyDatabaseId || !OidIsValid(msg->cc.dbId))
 		{
 			InvalidateCatalogSnapshot();
 
@@ -835,7 +835,7 @@ LocalExecuteInvalidationMessage(SharedInvalidationMessage *msg)
 	}
 	else if (msg->id == SHAREDINVALCATALOG_ID)
 	{
-		if (msg->cat.dbId == MyDatabaseId || msg->cat.dbId == InvalidOid)
+		if (msg->cat.dbId == MyDatabaseId || !OidIsValid(msg->cat.dbId))
 		{
 			InvalidateCatalogSnapshot();
 
@@ -846,11 +846,11 @@ LocalExecuteInvalidationMessage(SharedInvalidationMessage *msg)
 	}
 	else if (msg->id == SHAREDINVALRELCACHE_ID)
 	{
-		if (msg->rc.dbId == MyDatabaseId || msg->rc.dbId == InvalidOid)
+		if (msg->rc.dbId == MyDatabaseId || !OidIsValid(msg->rc.dbId))
 		{
 			int			i;
 
-			if (msg->rc.relId == InvalidOid)
+			if (!OidIsValid(msg->rc.relId))
 				RelationCacheInvalidate(false);
 			else
 				RelationCacheInvalidateEntry(msg->rc.relId);
@@ -878,7 +878,7 @@ LocalExecuteInvalidationMessage(SharedInvalidationMessage *msg)
 	else if (msg->id == SHAREDINVALRELMAP_ID)
 	{
 		/* We only care about our own database and shared catalogs */
-		if (msg->rm.dbId == InvalidOid)
+		if (!OidIsValid(msg->rm.dbId))
 			RelationMapInvalidate(true);
 		else if (msg->rm.dbId == MyDatabaseId)
 			RelationMapInvalidate(false);
@@ -886,7 +886,7 @@ LocalExecuteInvalidationMessage(SharedInvalidationMessage *msg)
 	else if (msg->id == SHAREDINVALSNAPSHOT_ID)
 	{
 		/* We only care about our own database and shared catalogs */
-		if (msg->sn.dbId == InvalidOid)
+		if (!OidIsValid(msg->sn.dbId))
 			InvalidateCatalogSnapshot();
 		else if (msg->sn.dbId == MyDatabaseId)
 			InvalidateCatalogSnapshot();
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index fa7cd7e06a7..1d2430d6233 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -3416,7 +3416,7 @@ get_attstatsslot(AttStatsSlot *sslot, HeapTuple statstuple,
 	for (i = 0; i < STATISTIC_NUM_SLOTS; i++)
 	{
 		if ((&stats->stakind1)[i] == reqkind &&
-			(reqop == InvalidOid || (&stats->staop1)[i] == reqop))
+			(!OidIsValid(reqop) || (&stats->staop1)[i] == reqop))
 			break;
 	}
 	if (i >= STATISTIC_NUM_SLOTS)
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index 6661d2c6b73..54772e6c260 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -2140,7 +2140,7 @@ PlanCacheRelCallback(Datum arg, Oid relid)
 		/*
 		 * Check the dependency list for the rewritten querytree.
 		 */
-		if ((relid == InvalidOid) ? plansource->relationOids != NIL :
+		if ((!OidIsValid(relid)) ? plansource->relationOids != NIL :
 			list_member_oid(plansource->relationOids, relid))
 		{
 			/* Invalidate the querytree and generic plan */
@@ -2163,7 +2163,7 @@ PlanCacheRelCallback(Datum arg, Oid relid)
 
 				if (plannedstmt->commandType == CMD_UTILITY)
 					continue;	/* Ignore utility statements */
-				if ((relid == InvalidOid) ? plannedstmt->relationOids != NIL :
+				if ((!OidIsValid(relid)) ? plannedstmt->relationOids != NIL :
 					list_member_oid(plannedstmt->relationOids, relid))
 				{
 					/* Invalidate the generic plan only */
@@ -2186,7 +2186,7 @@ PlanCacheRelCallback(Datum arg, Oid relid)
 		if (!cexpr->is_valid)
 			continue;
 
-		if ((relid == InvalidOid) ? cexpr->relationOids != NIL :
+		if ((!OidIsValid(relid)) ? cexpr->relationOids != NIL :
 			list_member_oid(cexpr->relationOids, relid))
 		{
 			cexpr->is_valid = false;
diff --git a/src/backend/utils/cache/relfilenumbermap.c b/src/backend/utils/cache/relfilenumbermap.c
index 0b6f9cf3fa1..3abd6f03282 100644
--- a/src/backend/utils/cache/relfilenumbermap.c
+++ b/src/backend/utils/cache/relfilenumbermap.c
@@ -65,8 +65,8 @@ RelfilenumberMapInvalidateCallback(Datum arg, Oid relid)
 		 * all entries, otherwise just remove the specific relation's entry.
 		 * Always remove negative cache entries.
 		 */
-		if (relid == InvalidOid ||	/* complete reset */
-			entry->relid == InvalidOid ||	/* negative cache entry */
+		if (!OidIsValid(relid) ||	/* complete reset */
+			!OidIsValid(entry->relid) ||	/* negative cache entry */
 			entry->relid == relid)	/* individual flushed relation */
 		{
 			if (hash_search(RelfilenumberMapHash,
diff --git a/src/backend/utils/cache/spccache.c b/src/backend/utils/cache/spccache.c
index 23458599298..657f1a8f9d3 100644
--- a/src/backend/utils/cache/spccache.c
+++ b/src/backend/utils/cache/spccache.c
@@ -114,7 +114,7 @@ get_tablespace(Oid spcid)
 	 * Since spcid is always from a pg_class tuple, InvalidOid implies the
 	 * default.
 	 */
-	if (spcid == InvalidOid)
+	if (!OidIsValid(spcid))
 		spcid = MyDatabaseTableSpace;
 
 	/* Find existing cache entry, if any. */
diff --git a/src/backend/utils/cache/ts_cache.c b/src/backend/utils/cache/ts_cache.c
index e8ae53238d0..4642d175d53 100644
--- a/src/backend/utils/cache/ts_cache.c
+++ b/src/backend/utils/cache/ts_cache.c
@@ -608,7 +608,7 @@ check_default_text_search_config(char **newval, void **extra, GucSource source)
 	 * cannot do the catalog accesses necessary to verify the config name.
 	 * Must accept it on faith.
 	 */
-	if (IsTransactionState() && MyDatabaseId != InvalidOid)
+	if (IsTransactionState() && OidIsValid(MyDatabaseId))
 	{
 		ErrorSaveContext escontext = {T_ErrorSaveContext};
 		List	   *namelist;
diff --git a/src/backend/utils/cache/typcache.c b/src/backend/utils/cache/typcache.c
index 6a347698edf..6757efbfb95 100644
--- a/src/backend/utils/cache/typcache.c
+++ b/src/backend/utils/cache/typcache.c
@@ -594,7 +594,7 @@ lookup_type_cache(Oid type_id, int flags)
 	 */
 	if ((flags & (TYPECACHE_EQ_OPR | TYPECACHE_EQ_OPR_FINFO)) &&
 		!(typentry->flags & TCFLAGS_CHECKED_EQ_OPR) &&
-		typentry->btree_opf == InvalidOid)
+		!OidIsValid(typentry->btree_opf))
 		flags |= TYPECACHE_HASH_OPFAMILY;
 
 	if ((flags & (TYPECACHE_HASH_PROC | TYPECACHE_HASH_PROC_FINFO |
@@ -634,13 +634,13 @@ lookup_type_cache(Oid type_id, int flags)
 	{
 		Oid			eq_opr = InvalidOid;
 
-		if (typentry->btree_opf != InvalidOid)
+		if (OidIsValid(typentry->btree_opf))
 			eq_opr = get_opfamily_member(typentry->btree_opf,
 										 typentry->btree_opintype,
 										 typentry->btree_opintype,
 										 BTEqualStrategyNumber);
-		if (eq_opr == InvalidOid &&
-			typentry->hash_opf != InvalidOid)
+		if (!OidIsValid(eq_opr) &&
+			OidIsValid(typentry->hash_opf))
 			eq_opr = get_opfamily_member(typentry->hash_opf,
 										 typentry->hash_opintype,
 										 typentry->hash_opintype,
@@ -681,7 +681,7 @@ lookup_type_cache(Oid type_id, int flags)
 	{
 		Oid			lt_opr = InvalidOid;
 
-		if (typentry->btree_opf != InvalidOid)
+		if (OidIsValid(typentry->btree_opf))
 			lt_opr = get_opfamily_member(typentry->btree_opf,
 										 typentry->btree_opintype,
 										 typentry->btree_opintype,
@@ -706,7 +706,7 @@ lookup_type_cache(Oid type_id, int flags)
 	{
 		Oid			gt_opr = InvalidOid;
 
-		if (typentry->btree_opf != InvalidOid)
+		if (OidIsValid(typentry->btree_opf))
 			gt_opr = get_opfamily_member(typentry->btree_opf,
 										 typentry->btree_opintype,
 										 typentry->btree_opintype,
@@ -731,7 +731,7 @@ lookup_type_cache(Oid type_id, int flags)
 	{
 		Oid			cmp_proc = InvalidOid;
 
-		if (typentry->btree_opf != InvalidOid)
+		if (OidIsValid(typentry->btree_opf))
 			cmp_proc = get_opfamily_proc(typentry->btree_opf,
 										 typentry->btree_opintype,
 										 typentry->btree_opintype,
@@ -764,7 +764,7 @@ lookup_type_cache(Oid type_id, int flags)
 		 * We insist that the eq_opr, if one has been determined, match the
 		 * hash opclass; else report there is no hash function.
 		 */
-		if (typentry->hash_opf != InvalidOid &&
+		if (OidIsValid(typentry->hash_opf) &&
 			(!OidIsValid(typentry->eq_opr) ||
 			 typentry->eq_opr == get_opfamily_member(typentry->hash_opf,
 													 typentry->hash_opintype,
@@ -813,7 +813,7 @@ lookup_type_cache(Oid type_id, int flags)
 		 * We insist that the eq_opr, if one has been determined, match the
 		 * hash opclass; else report there is no hash function.
 		 */
-		if (typentry->hash_opf != InvalidOid &&
+		if (OidIsValid(typentry->hash_opf) &&
 			(!OidIsValid(typentry->eq_opr) ||
 			 typentry->eq_opr == get_opfamily_member(typentry->hash_opf,
 													 typentry->hash_opintype,
@@ -866,33 +866,33 @@ lookup_type_cache(Oid type_id, int flags)
 	 * that would cause session-lifespan memory leaks.
 	 */
 	if ((flags & TYPECACHE_EQ_OPR_FINFO) &&
-		typentry->eq_opr_finfo.fn_oid == InvalidOid &&
-		typentry->eq_opr != InvalidOid)
+		!OidIsValid(typentry->eq_opr_finfo.fn_oid) &&
+		OidIsValid(typentry->eq_opr))
 	{
 		Oid			eq_opr_func;
 
 		eq_opr_func = get_opcode(typentry->eq_opr);
-		if (eq_opr_func != InvalidOid)
+		if (OidIsValid(eq_opr_func))
 			fmgr_info_cxt(eq_opr_func, &typentry->eq_opr_finfo,
 						  CacheMemoryContext);
 	}
 	if ((flags & TYPECACHE_CMP_PROC_FINFO) &&
-		typentry->cmp_proc_finfo.fn_oid == InvalidOid &&
-		typentry->cmp_proc != InvalidOid)
+		!OidIsValid(typentry->cmp_proc_finfo.fn_oid) &&
+		OidIsValid(typentry->cmp_proc))
 	{
 		fmgr_info_cxt(typentry->cmp_proc, &typentry->cmp_proc_finfo,
 					  CacheMemoryContext);
 	}
 	if ((flags & TYPECACHE_HASH_PROC_FINFO) &&
-		typentry->hash_proc_finfo.fn_oid == InvalidOid &&
-		typentry->hash_proc != InvalidOid)
+		!OidIsValid(typentry->hash_proc_finfo.fn_oid) &&
+		OidIsValid(typentry->hash_proc))
 	{
 		fmgr_info_cxt(typentry->hash_proc, &typentry->hash_proc_finfo,
 					  CacheMemoryContext);
 	}
 	if ((flags & TYPECACHE_HASH_EXTENDED_PROC_FINFO) &&
-		typentry->hash_extended_proc_finfo.fn_oid == InvalidOid &&
-		typentry->hash_extended_proc != InvalidOid)
+		!OidIsValid(typentry->hash_extended_proc_finfo.fn_oid) &&
+		OidIsValid(typentry->hash_extended_proc))
 	{
 		fmgr_info_cxt(typentry->hash_extended_proc,
 					  &typentry->hash_extended_proc_finfo,
@@ -938,7 +938,7 @@ lookup_type_cache(Oid type_id, int flags)
 	 * If requested, get information about a domain type
 	 */
 	if ((flags & TYPECACHE_DOMAIN_BASE_INFO) &&
-		typentry->domainBaseType == InvalidOid &&
+		!OidIsValid(typentry->domainBaseType) &&
 		typentry->typtype == TYPTYPE_DOMAIN)
 	{
 		typentry->domainBaseTypmod = -1;
@@ -1678,7 +1678,7 @@ cache_record_field_properties(TypeCacheEntry *typentry)
 		TypeCacheEntry *baseentry;
 
 		/* load up basetype info if we didn't already */
-		if (typentry->domainBaseType == InvalidOid)
+		if (!OidIsValid(typentry->domainBaseType))
 		{
 			typentry->domainBaseTypmod = -1;
 			typentry->domainBaseType =
diff --git a/src/backend/utils/fmgr/funcapi.c b/src/backend/utils/fmgr/funcapi.c
index 5f2317211c9..98b88b12231 100644
--- a/src/backend/utils/fmgr/funcapi.c
+++ b/src/backend/utils/fmgr/funcapi.c
@@ -490,7 +490,7 @@ internal_get_result_type(Oid funcid,
 	{
 		Oid			newrettype = exprType(call_expr);
 
-		if (newrettype == InvalidOid)	/* this probably should not happen */
+		if (!OidIsValid(newrettype))	/* this probably should not happen */
 			ereport(ERROR,
 					(errcode(ERRCODE_DATATYPE_MISMATCH),
 					 errmsg("could not determine actual result type for function \"%s\" declared to return type %s",
diff --git a/src/backend/utils/misc/queryenvironment.c b/src/backend/utils/misc/queryenvironment.c
index 7bc72dabe67..8ae1783bc0e 100644
--- a/src/backend/utils/misc/queryenvironment.c
+++ b/src/backend/utils/misc/queryenvironment.c
@@ -127,7 +127,7 @@ ENRMetadataGetTupDesc(EphemeralNamedRelationMetadata enrmd)
 	TupleDesc	tupdesc;
 
 	/* One, and only one, of these fields must be filled. */
-	Assert((enrmd->reliddesc == InvalidOid) != (enrmd->tupdesc == NULL));
+	Assert((!OidIsValid(enrmd->reliddesc)) != (enrmd->tupdesc == NULL));
 
 	if (enrmd->tupdesc != NULL)
 		tupdesc = enrmd->tupdesc;
diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c
index 4e7303ea631..bc1d3a7adc8 100644
--- a/src/bin/pg_dump/common.c
+++ b/src/bin/pg_dump/common.c
@@ -402,7 +402,7 @@ flagInhIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
 			IndxInfo   *parentidx;
 			IndexAttachInfo *attachinfo;
 
-			if (index->parentidx == 0)
+			if (!OidIsValid(index->parentidx))
 				continue;
 
 			parentidx = findIndexByOid(index->parentidx);
diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c
index c84b017f21b..0122ec6239d 100644
--- a/src/bin/pg_dump/pg_backup_archiver.c
+++ b/src/bin/pg_dump/pg_backup_archiver.c
@@ -1518,7 +1518,7 @@ StartRestoreLO(ArchiveHandle *AH, Oid oid, bool drop)
 		if (old_lo_style)
 		{
 			loOid = lo_create(AH->connection, oid);
-			if (loOid == 0 || loOid != oid)
+			if (!OidIsValid(loOid) || loOid != oid)
 				pg_fatal("could not create large object %u: %s",
 						 oid, PQerrorMessage(AH->connection));
 		}
diff --git a/src/bin/pg_dump/pg_backup_custom.c b/src/bin/pg_dump/pg_backup_custom.c
index 2226520dffc..d2ea2397181 100644
--- a/src/bin/pg_dump/pg_backup_custom.c
+++ b/src/bin/pg_dump/pg_backup_custom.c
@@ -371,7 +371,7 @@ _StartLO(ArchiveHandle *AH, TocEntry *te, Oid oid)
 {
 	lclContext *ctx = (lclContext *) AH->formatData;
 
-	if (oid == 0)
+	if (!OidIsValid(oid))
 		pg_fatal("invalid OID for large object");
 
 	WriteInt(AH, oid);
@@ -583,7 +583,7 @@ _LoadLOs(ArchiveHandle *AH, bool drop)
 	StartRestoreLOs(AH);
 
 	oid = ReadInt(AH);
-	while (oid != 0)
+	while (OidIsValid(oid))
 	{
 		StartRestoreLO(AH, oid, drop);
 		_PrintData(AH);
@@ -606,7 +606,7 @@ _skipLOs(ArchiveHandle *AH)
 	Oid			oid;
 
 	oid = ReadInt(AH);
-	while (oid != 0)
+	while (OidIsValid(oid))
 	{
 		_skipData(AH);
 		oid = ReadInt(AH);
diff --git a/src/bin/pg_dump/pg_backup_null.c b/src/bin/pg_dump/pg_backup_null.c
index a3257f4fc84..a3bc2f93605 100644
--- a/src/bin/pg_dump/pg_backup_null.c
+++ b/src/bin/pg_dump/pg_backup_null.c
@@ -139,7 +139,7 @@ _StartLO(ArchiveHandle *AH, TocEntry *te, Oid oid)
 {
 	bool		old_lo_style = (AH->version < K_VERS_1_12);
 
-	if (oid == 0)
+	if (!OidIsValid(oid))
 		pg_fatal("invalid OID for large object");
 
 	/* With an old archive we must do drop and create logic here */
diff --git a/src/bin/pg_dump/pg_backup_tar.c b/src/bin/pg_dump/pg_backup_tar.c
index b5ba3b46dd9..991ec51137e 100644
--- a/src/bin/pg_dump/pg_backup_tar.c
+++ b/src/bin/pg_dump/pg_backup_tar.c
@@ -678,7 +678,7 @@ _LoadLOs(ArchiveHandle *AH, TocEntry *te)
 		if (strncmp(th->targetFile, "blob_", 5) == 0)
 		{
 			oid = atooid(&th->targetFile[5]);
-			if (oid != 0)
+			if (OidIsValid(oid))
 			{
 				pg_log_info("restoring large object with OID %u", oid);
 
@@ -899,7 +899,7 @@ _StartLO(ArchiveHandle *AH, TocEntry *te, Oid oid)
 	lclTocEntry *tctx = (lclTocEntry *) te->formatData;
 	char		fname[255];
 
-	if (oid == 0)
+	if (!OidIsValid(oid))
 		pg_fatal("invalid OID for large object (%u)", oid);
 
 	if (AH->compression_spec.algorithm != PG_COMPRESSION_NONE)
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index a00918bacb4..253c2369897 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -8120,7 +8120,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
 				NULL, NULL
 			};
 
-			if (indxinfo[j].parentidx == 0)
+			if (!OidIsValid(indxinfo->parentidx))
 				indexkind = RELKIND_INDEX;
 			else
 				indexkind = RELKIND_PARTITIONED_INDEX;
@@ -8397,7 +8397,7 @@ getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
 		{
 			Oid			indexOid = atooid(PQgetvalue(res, j, i_conindid));
 
-			if (indexOid != InvalidOid)
+			if (OidIsValid(indexOid))
 			{
 				for (int k = 0; k < reftable->numIndexes; k++)
 				{
@@ -10633,7 +10633,7 @@ getDefaultACLs(Archive *fout)
 		/* cheesy ... is it worth coming up with a better object name? */
 		daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
 
-		if (nspid != InvalidOid)
+		if (OidIsValid(nspid))
 			daclinfo[i].dobj.namespace = findNamespace(nspid);
 		else
 			daclinfo[i].dobj.namespace = NULL;
@@ -14005,10 +14005,10 @@ dumpTransform(Archive *fout, const TransformInfo *transform)
 	appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
 					  transformType, lanname);
 
-	if (!transform->trffromsql && !transform->trftosql)
+	if (!OidIsValid(transform->trffromsql) && !OidIsValid(transform->trftosql))
 		pg_log_warning("bogus transform definition, at least one of trffromsql and trftosql should be nonzero");
 
-	if (transform->trffromsql)
+	if (OidIsValid(transform->trffromsql))
 	{
 		if (fromsqlFuncInfo)
 		{
@@ -14026,9 +14026,9 @@ dumpTransform(Archive *fout, const TransformInfo *transform)
 			pg_log_warning("bogus value in pg_transform.trffromsql field");
 	}
 
-	if (transform->trftosql)
+	if (OidIsValid(transform->trftosql))
 	{
-		if (transform->trffromsql)
+		if (OidIsValid(transform->trffromsql))
 			appendPQExpBufferStr(defqry, ", ");
 
 		if (tosqlFuncInfo)
@@ -15738,7 +15738,7 @@ dumpTSParser(Archive *fout, const TSParserInfo *prsinfo)
 					  convertTSFunction(fout, prsinfo->prstoken));
 	appendPQExpBuffer(q, "    END = %s,\n",
 					  convertTSFunction(fout, prsinfo->prsend));
-	if (prsinfo->prsheadline != InvalidOid)
+	if (OidIsValid(prsinfo->prsheadline))
 		appendPQExpBuffer(q, "    HEADLINE = %s,\n",
 						  convertTSFunction(fout, prsinfo->prsheadline));
 	appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
@@ -15876,7 +15876,7 @@ dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo)
 	appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
 					  fmtQualifiedDumpable(tmplinfo));
 
-	if (tmplinfo->tmplinit != InvalidOid)
+	if (OidIsValid(tmplinfo->tmplinit))
 		appendPQExpBuffer(q, "    INIT = %s,\n",
 						  convertTSFunction(fout, tmplinfo->tmplinit));
 	appendPQExpBuffer(q, "    LEXIZE = %s );\n",
@@ -17788,7 +17788,7 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
 			appendStringLiteralAH(q, qualrelname, fout);
 			appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
 
-			if (tbinfo->toast_oid)
+			if (OidIsValid(tbinfo->toast_oid))
 			{
 				/*
 				 * The toast table will have the same OID at restore, so we
@@ -18361,7 +18361,7 @@ dumpIndex(Archive *fout, const IndxInfo *indxinfo)
 		 * But that's fine, and even if you think it's not, the backend won't
 		 * let us do differently.)
 		 */
-		if (indxinfo->parentidx == 0)
+		if (!OidIsValid(indxinfo->parentidx))
 			appendPQExpBuffer(delq, "DROP INDEX %s;\n", qqindxname);
 
 		if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
@@ -20357,7 +20357,7 @@ getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
 	PQExpBuffer query;
 	PGresult   *res;
 
-	if (oid == 0)
+	if (!OidIsValid(oid))
 	{
 		if ((opts & zeroAsStar) != 0)
 			return "*";
diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c
index a31e7643cf0..ebdbffc1336 100644
--- a/src/bin/pg_resetwal/pg_resetwal.c
+++ b/src/bin/pg_resetwal/pg_resetwal.c
@@ -236,7 +236,7 @@ main(int argc, char *argv[])
 					pg_log_error_hint("Try \"%s --help\" for more information.", progname);
 					exit(1);
 				}
-				if (set_oid == 0)
+				if (!OidIsValid(set_oid))
 					pg_fatal("OID (-o) must not be 0");
 				break;
 
@@ -456,7 +456,7 @@ main(int argc, char *argv[])
 	if (set_newest_commit_ts_xid != 0)
 		ControlFile.checkPointCopy.newestCommitTsXid = set_newest_commit_ts_xid;
 
-	if (set_oid != 0)
+	if (OidIsValid(set_oid))
 		ControlFile.checkPointCopy.nextOid = set_oid;
 
 	if (mxid_given)
@@ -829,7 +829,7 @@ PrintNewControlValues(void)
 			   ControlFile.checkPointCopy.nextMultiOffset);
 	}
 
-	if (set_oid != 0)
+	if (OidIsValid(set_oid))
 	{
 		printf(_("NextOID:                              %u\n"),
 			   ControlFile.checkPointCopy.nextOid);
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 36f24502842..94e1c774f6f 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -3693,7 +3693,7 @@ add_tablespace_footer(printTableContent *const cont, char relkind,
 		 * We ignore the database default tablespace so that users not using
 		 * tablespaces don't need to know about them.
 		 */
-		if (tablespace != 0)
+		if (OidIsValid(tablespace))
 		{
 			PGresult   *result = NULL;
 			PQExpBufferData buf;
diff --git a/src/bin/psql/large_obj.c b/src/bin/psql/large_obj.c
index 28f8c414b67..22032ec2c92 100644
--- a/src/bin/psql/large_obj.c
+++ b/src/bin/psql/large_obj.c
@@ -187,7 +187,7 @@ do_lo_import(const char *filename_arg, const char *comment_arg)
 	loid = lo_import(pset.db, filename_arg);
 	ResetCancelConn();
 
-	if (loid == InvalidOid)
+	if (!OidIsValid(loid))
 	{
 		pg_log_info("%s", PQerrorMessage(pset.db));
 		return fail_lo_xact("\\lo_import", own_transaction);
diff --git a/src/common/relpath.c b/src/common/relpath.c
index 7dcf987afcd..786f915a788 100644
--- a/src/common/relpath.c
+++ b/src/common/relpath.c
@@ -112,7 +112,7 @@ GetDatabasePath(Oid dbOid, Oid spcOid)
 	if (spcOid == GLOBALTABLESPACE_OID)
 	{
 		/* Shared system relations live in {datadir}/global */
-		Assert(dbOid == 0);
+		Assert(!OidIsValid(dbOid));
 		return pstrdup("global");
 	}
 	else if (spcOid == DEFAULTTABLESPACE_OID)
@@ -148,7 +148,7 @@ GetRelationPath(Oid dbOid, Oid spcOid, RelFileNumber relNumber,
 	if (spcOid == GLOBALTABLESPACE_OID)
 	{
 		/* Shared system relations live in {datadir}/global */
-		Assert(dbOid == 0);
+		Assert(!OidIsValid(dbOid));
 		Assert(procNumber == INVALID_PROC_NUMBER);
 		if (forkNumber != MAIN_FORKNUM)
 			sprintf(rp.str, "global/%u_%s",
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c
index 05e17bed508..b1c1dfbe146 100644
--- a/src/interfaces/libpq/fe-lobj.c
+++ b/src/interfaces/libpq/fe-lobj.c
@@ -139,7 +139,7 @@ lo_truncate(PGconn *conn, int fd, size_t len)
 		return -1;
 
 	/* Must check this on-the-fly because it's not there pre-8.3 */
-	if (conn->lobjfuncs->fn_lo_truncate == 0)
+	if (!OidIsValid(conn->lobjfuncs->fn_lo_truncate))
 	{
 		libpq_append_conn_error(conn, "cannot determine OID of function %s",
 								"lo_truncate");
@@ -202,7 +202,7 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
 	if (lo_initialize(conn) < 0)
 		return -1;
 
-	if (conn->lobjfuncs->fn_lo_truncate64 == 0)
+	if (!OidIsValid(conn->lobjfuncs->fn_lo_truncate64))
 	{
 		libpq_append_conn_error(conn, "cannot determine OID of function %s",
 								"lo_truncate64");
@@ -392,7 +392,7 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
 	if (lo_initialize(conn) < 0)
 		return -1;
 
-	if (conn->lobjfuncs->fn_lo_lseek64 == 0)
+	if (!OidIsValid(conn->lobjfuncs->fn_lo_lseek64))
 	{
 		libpq_append_conn_error(conn, "cannot determine OID of function %s",
 								"lo_lseek64");
@@ -482,7 +482,7 @@ lo_create(PGconn *conn, Oid lobjId)
 		return InvalidOid;
 
 	/* Must check this on-the-fly because it's not there pre-8.1 */
-	if (conn->lobjfuncs->fn_lo_create == 0)
+	if (!OidIsValid(conn->lobjfuncs->fn_lo_create))
 	{
 		libpq_append_conn_error(conn, "cannot determine OID of function %s",
 								"lo_create");
@@ -555,7 +555,7 @@ lo_tell64(PGconn *conn, int fd)
 	if (lo_initialize(conn) < 0)
 		return -1;
 
-	if (conn->lobjfuncs->fn_lo_tell64 == 0)
+	if (!OidIsValid(conn->lobjfuncs->fn_lo_tell64))
 	{
 		libpq_append_conn_error(conn, "cannot determine OID of function %s",
 								"lo_tell64");
@@ -674,12 +674,12 @@ lo_import_internal(PGconn *conn, const char *filename, Oid oid)
 	/*
 	 * create an inversion object
 	 */
-	if (oid == InvalidOid)
+	if (!OidIsValid(oid))
 		lobjOid = lo_creat(conn, INV_READ | INV_WRITE);
 	else
 		lobjOid = lo_create(conn, oid);
 
-	if (lobjOid == InvalidOid)
+	if (!OidIsValid(lobjOid))
 	{
 		/* we assume lo_create() already set a suitable error message */
 		(void) close(fd);
@@ -951,56 +951,56 @@ lo_initialize(PGconn *conn)
 	 * (ones that have been added later than the stone age are instead checked
 	 * only if used)
 	 */
-	if (lobjfuncs->fn_lo_open == 0)
+	if (!OidIsValid(lobjfuncs->fn_lo_open))
 	{
 		libpq_append_conn_error(conn, "cannot determine OID of function %s",
 								"lo_open");
 		free(lobjfuncs);
 		return -1;
 	}
-	if (lobjfuncs->fn_lo_close == 0)
+	if (!OidIsValid(lobjfuncs->fn_lo_close))
 	{
 		libpq_append_conn_error(conn, "cannot determine OID of function %s",
 								"lo_close");
 		free(lobjfuncs);
 		return -1;
 	}
-	if (lobjfuncs->fn_lo_creat == 0)
+	if (!OidIsValid(lobjfuncs->fn_lo_creat))
 	{
 		libpq_append_conn_error(conn, "cannot determine OID of function %s",
 								"lo_creat");
 		free(lobjfuncs);
 		return -1;
 	}
-	if (lobjfuncs->fn_lo_unlink == 0)
+	if (!OidIsValid(lobjfuncs->fn_lo_unlink))
 	{
 		libpq_append_conn_error(conn, "cannot determine OID of function %s",
 								"lo_unlink");
 		free(lobjfuncs);
 		return -1;
 	}
-	if (lobjfuncs->fn_lo_lseek == 0)
+	if (!OidIsValid(lobjfuncs->fn_lo_lseek))
 	{
 		libpq_append_conn_error(conn, "cannot determine OID of function %s",
 								"lo_lseek");
 		free(lobjfuncs);
 		return -1;
 	}
-	if (lobjfuncs->fn_lo_tell == 0)
+	if (!OidIsValid(lobjfuncs->fn_lo_tell))
 	{
 		libpq_append_conn_error(conn, "cannot determine OID of function %s",
 								"lo_tell");
 		free(lobjfuncs);
 		return -1;
 	}
-	if (lobjfuncs->fn_lo_read == 0)
+	if (!OidIsValid(lobjfuncs->fn_lo_read))
 	{
 		libpq_append_conn_error(conn, "cannot determine OID of function %s",
 								"loread");
 		free(lobjfuncs);
 		return -1;
 	}
-	if (lobjfuncs->fn_lo_write == 0)
+	if (!OidIsValid(lobjfuncs->fn_lo_write))
 	{
 		libpq_append_conn_error(conn, "cannot determine OID of function %s",
 								"lowrite");
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 73ba1748fe0..f25216ddfeb 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1270,7 +1270,7 @@ plperl_array_to_datum(SV *src, Oid typid, int32 typmod)
 	int			i;
 
 	elemtypid = get_element_type(typid);
-	if (!elemtypid)
+	if (!OidIsValid(elemtypid))
 		ereport(ERROR,
 				(errcode(ERRCODE_DATATYPE_MISMATCH),
 				 errmsg("cannot convert Perl array to non-array type %s",
@@ -1352,7 +1352,7 @@ plperl_sv_to_datum(SV *sv, Oid typid, int32 typmod,
 		/* must call typinput in case it wants to reject NULL */
 		return InputFunctionCall(finfo, NULL, typioparam, typmod);
 	}
-	else if ((funcid = get_transform_tosql(typid, current_call_data->prodesc->lang_oid, current_call_data->prodesc->trftypes)))
+	else if (OidIsValid((funcid = get_transform_tosql(typid, current_call_data->prodesc->lang_oid, current_call_data->prodesc->trftypes))))
 		return OidFunctionCall1(funcid, PointerGetDatum(sv));
 	else if (SvROK(sv))
 	{
@@ -1612,7 +1612,7 @@ make_array_ref(plperl_array_info *info, int first, int last)
 		{
 			Datum		itemvalue = info->elements[i];
 
-			if (info->transform_proc.fn_oid)
+			if (OidIsValid(info->transform_proc.fn_oid))
 				av_push(result, (SV *) DatumGetPointer(FunctionCall1(&info->transform_proc, itemvalue)));
 			else if (info->elem_is_rowtype)
 				/* Handle composite type elements */
@@ -2195,7 +2195,7 @@ plperl_call_perl_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo)
 	EXTEND(sp, desc->nargs);
 
 	/* Get signature for true functions; inline blocks have no args. */
-	if (fcinfo->flinfo->fn_oid)
+	if (OidIsValid(fcinfo->flinfo->fn_oid))
 		get_func_signature(fcinfo->flinfo->fn_oid, &argtypes, &nargs);
 	Assert(nargs == desc->nargs);
 
@@ -2494,7 +2494,7 @@ plperl_func_handler(PG_FUNCTION_ARGS)
 		}
 		retval = (Datum) 0;
 	}
-	else if (prodesc->result_oid)
+	else if (OidIsValid(prodesc->result_oid))
 	{
 		retval = plperl_sv_to_datum(perlret,
 									prodesc->result_oid,
@@ -3378,7 +3378,7 @@ plperl_return_next_internal(SV *sv)
 
 		tuplestore_puttuple(current_call_data->tuple_store, tuple);
 	}
-	else if (prodesc->result_oid)
+	else if (OidIsValid(prodesc->result_oid))
 	{
 		Datum		ret[1];
 		bool		isNull[1];
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index d19425b7a71..28e616cacfb 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -3083,11 +3083,11 @@ exec_stmt_foreach_a(PLpgSQL_execstate *estate, PLpgSQL_stmt_foreach_a *stmt)
 	 * coerce values of different types.  But it seems worthwhile to complain
 	 * if the array-ness of the loop variable is not right.
 	 */
-	if (stmt->slice > 0 && loop_var_elem_type == InvalidOid)
+	if (stmt->slice > 0 && !OidIsValid(loop_var_elem_type))
 		ereport(ERROR,
 				(errcode(ERRCODE_DATATYPE_MISMATCH),
 				 errmsg("FOREACH ... SLICE loop variable must be of an array type")));
-	if (stmt->slice == 0 && loop_var_elem_type != InvalidOid)
+	if (stmt->slice == 0 && OidIsValid(loop_var_elem_type))
 		ereport(ERROR,
 				(errcode(ERRCODE_DATATYPE_MISMATCH),
 				 errmsg("FOREACH loop variable must not be of an array type")));
diff --git a/src/pl/plpython/plpy_procedure.c b/src/pl/plpython/plpy_procedure.c
index 655ab1d09ee..03567e15620 100644
--- a/src/pl/plpython/plpy_procedure.c
+++ b/src/pl/plpython/plpy_procedure.c
@@ -77,7 +77,7 @@ PLy_procedure_get(Oid fn_oid, Oid fn_rel, PLyTrigType is_trigger)
 	PLyProcedure *volatile proc = NULL;
 	bool		found = false;
 
-	if (is_trigger == PLPY_TRIGGER && fn_rel == InvalidOid)
+	if (is_trigger == PLPY_TRIGGER && !OidIsValid(fn_rel))
 		use_cache = false;
 	else
 		use_cache = true;
diff --git a/src/pl/plpython/plpy_typeio.c b/src/pl/plpython/plpy_typeio.c
index d88d10068f3..1b7882d35db 100644
--- a/src/pl/plpython/plpy_typeio.c
+++ b/src/pl/plpython/plpy_typeio.c
@@ -367,9 +367,7 @@ PLy_output_setup_func(PLyObToDatum *arg, MemoryContext arg_mcxt,
 							  typentry->typelem, typmod,
 							  proc);
 	}
-	else if ((trfuncid = get_transform_tosql(typeOid,
-											 proc->langid,
-											 proc->trftypes)))
+	else if (OidIsValid((trfuncid = get_transform_tosql(typeOid, proc->langid, proc->trftypes))))
 	{
 		arg->func = PLyObject_ToTransform;
 		fmgr_info_cxt(trfuncid, &arg->transform.typtransform, arg_mcxt);
@@ -482,9 +480,7 @@ PLy_input_setup_func(PLyDatumToOb *arg, MemoryContext arg_mcxt,
 							 typentry->typelem, typmod,
 							 proc);
 	}
-	else if ((trfuncid = get_transform_fromsql(typeOid,
-											   proc->langid,
-											   proc->trftypes)))
+	else if (OidIsValid((trfuncid = get_transform_fromsql(typeOid, proc->langid, proc->trftypes))))
 	{
 		arg->func = PLyObject_FromTransform;
 		fmgr_info_cxt(trfuncid, &arg->transform.typtransform, arg_mcxt);
diff --git a/src/test/examples/testlo.c b/src/test/examples/testlo.c
index 2277000eddb..6f53908e4bf 100644
--- a/src/test/examples/testlo.c
+++ b/src/test/examples/testlo.c
@@ -53,7 +53,7 @@ importFile(PGconn *conn, char *filename)
 	 * create the large object
 	 */
 	lobjId = lo_creat(conn, INV_READ | INV_WRITE);
-	if (lobjId == 0)
+	if (!OidIsValid(lobjId))
 		fprintf(stderr, "cannot create large object");
 
 	lobj_fd = lo_open(conn, lobjId, INV_WRITE);
@@ -245,7 +245,7 @@ main(int argc, char **argv)
 	printf("importing file \"%s\" ...\n", in_filename);
 /*	lobjOid = importFile(conn, in_filename); */
 	lobjOid = lo_import(conn, in_filename);
-	if (lobjOid == 0)
+	if (!OidIsValid(lobjOid))
 		fprintf(stderr, "%s\n", PQerrorMessage(conn));
 	else
 	{
diff --git a/src/test/examples/testlo64.c b/src/test/examples/testlo64.c
index c303db92e5b..2b8bb1fa0f7 100644
--- a/src/test/examples/testlo64.c
+++ b/src/test/examples/testlo64.c
@@ -54,7 +54,7 @@ importFile(PGconn *conn, char *filename)
 	 * create the large object
 	 */
 	lobjId = lo_creat(conn, INV_READ | INV_WRITE);
-	if (lobjId == 0)
+	if (!OidIsValid(lobjId))
 		fprintf(stderr, "cannot create large object");
 
 	lobj_fd = lo_open(conn, lobjId, INV_WRITE);
@@ -270,7 +270,7 @@ main(int argc, char **argv)
 	printf("importing file \"%s\" ...\n", in_filename);
 /*	lobjOid = importFile(conn, in_filename); */
 	lobjOid = lo_import(conn, in_filename);
-	if (lobjOid == 0)
+	if (!OidIsValid(lobjOid))
 		fprintf(stderr, "%s\n", PQerrorMessage(conn));
 	else
 	{
-- 
2.34.1

v1-0003-Use-OidIsValid-in-various-places-for-pointers.patchtext/x-diff; charset=us-asciiDownload
From 81b59c71967e7f6e68316a67124501472b57d55a Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Sat, 15 Nov 2025 17:57:51 +0000
Subject: [PATCH v1 3/8] Use OidIsValid() in various places for pointers

Let's use OidIsValid() instead of:

- direct pointer comparisons with InvalidOid
- direct pointer comparisons with literal 0
---
 src/backend/parser/parse_param.c           | 2 +-
 src/backend/utils/sort/tuplesortvariants.c | 2 +-
 src/bin/pg_dump/pg_dump.c                  | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)
  27.2% src/backend/parser/
  36.1% src/backend/utils/sort/
  36.6% src/bin/pg_dump/

diff --git a/src/backend/parser/parse_param.c b/src/backend/parser/parse_param.c
index 930921626b6..bdbb2872ce6 100644
--- a/src/backend/parser/parse_param.c
+++ b/src/backend/parser/parse_param.c
@@ -157,7 +157,7 @@ variable_paramref_hook(ParseState *pstate, ParamRef *pref)
 	pptype = &(*parstate->paramTypes)[paramno - 1];
 
 	/* If not seen before, initialize to UNKNOWN type */
-	if (*pptype == InvalidOid)
+	if (!OidIsValid(*pptype))
 		*pptype = UNKNOWNOID;
 
 	/*
diff --git a/src/backend/utils/sort/tuplesortvariants.c b/src/backend/utils/sort/tuplesortvariants.c
index 41ac4afbf49..8aabae27e75 100644
--- a/src/backend/utils/sort/tuplesortvariants.c
+++ b/src/backend/utils/sort/tuplesortvariants.c
@@ -222,7 +222,7 @@ tuplesort_begin_heap(TupleDesc tupDesc,
 		SortSupport sortKey = base->sortKeys + i;
 
 		Assert(attNums[i] != 0);
-		Assert(sortOperators[i] != 0);
+		Assert(OidIsValid(sortOperators[i]));
 
 		sortKey->ssup_cxt = CurrentMemoryContext;
 		sortKey->ssup_collation = sortCollations[i];
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 253c2369897..8be4714cd4b 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -13669,7 +13669,7 @@ dumpFunc(Archive *fout, const FuncInfo *finfo)
 
 		appendPQExpBufferStr(q, " TRANSFORM ");
 		parseOidArray(protrftypes, typeids, FUNC_MAX_ARGS);
-		for (i = 0; typeids[i]; i++)
+		for (i = 0; OidIsValid(typeids[i]); i++)
 		{
 			if (i != 0)
 				appendPQExpBufferStr(q, ", ");
-- 
2.34.1

v1-0004-Use-OidIsValid-in-various-places-for-CATALOG.patchtext/x-diff; charset=us-asciiDownload
From 809b5f0d28dbc69388ce8e28c12df0ea9573eadb Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Mon, 17 Nov 2025 08:18:18 +0000
Subject: [PATCH v1 4/8] Use OidIsValid() in various places for CATALOG

Let's use OidIsValid() instead of:

- direct comparisons with InvalidOid
- direct comparisons with literal 0
---
 contrib/amcheck/verify_heapam.c               |  4 ++--
 contrib/test_decoding/test_decoding.c         |  2 +-
 src/backend/access/heap/heaptoast.c           |  6 +++---
 src/backend/bootstrap/bootstrap.c             |  2 +-
 src/backend/catalog/pg_constraint.c           |  2 +-
 src/backend/catalog/pg_shdepend.c             |  6 +++---
 src/backend/catalog/toasting.c                |  2 +-
 src/backend/commands/cluster.c                | 18 ++++++++---------
 src/backend/commands/tablecmds.c              | 16 +++++++--------
 src/backend/parser/parse_relation.c           |  2 +-
 .../replication/logical/reorderbuffer.c       |  2 +-
 src/backend/utils/adt/dbsize.c                |  6 +++---
 src/backend/utils/adt/regproc.c               |  8 ++++----
 src/backend/utils/adt/ruleutils.c             |  6 +++---
 src/backend/utils/cache/relcache.c            | 20 +++++++++----------
 15 files changed, 51 insertions(+), 51 deletions(-)
   4.4% contrib/amcheck/
   5.8% src/backend/access/heap/
   8.0% src/backend/catalog/
  35.4% src/backend/commands/
  14.4% src/backend/utils/adt/
  22.6% src/backend/utils/cache/
   7.2% src/backend/

diff --git a/contrib/amcheck/verify_heapam.c b/contrib/amcheck/verify_heapam.c
index 4963e9245cb..a5b97b0eea0 100644
--- a/contrib/amcheck/verify_heapam.c
+++ b/contrib/amcheck/verify_heapam.c
@@ -405,7 +405,7 @@ verify_heapam(PG_FUNCTION_ARGS)
 	}
 
 	/* Optionally open the toast relation, if any. */
-	if (ctx.rel->rd_rel->reltoastrelid && check_toast)
+	if (OidIsValid(ctx.rel->rd_rel->reltoastrelid) && check_toast)
 	{
 		int			offset;
 
@@ -1817,7 +1817,7 @@ check_tuple_attribute(HeapCheckContext *ctx)
 	}
 
 	/* The relation better have a toast table */
-	if (!ctx->rel->rd_rel->reltoastrelid)
+	if (!OidIsValid(ctx->rel->rd_rel->reltoastrelid))
 	{
 		report_corruption(ctx,
 						  psprintf("toast value %u is external but relation has no toast relation",
diff --git a/contrib/test_decoding/test_decoding.c b/contrib/test_decoding/test_decoding.c
index 36e77c69e1c..9dcbeb7fc8d 100644
--- a/contrib/test_decoding/test_decoding.c
+++ b/contrib/test_decoding/test_decoding.c
@@ -630,7 +630,7 @@ pg_decode_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
 	appendStringInfoString(ctx->out, "table ");
 	appendStringInfoString(ctx->out,
 						   quote_qualified_identifier(get_namespace_name(get_rel_namespace(RelationGetRelid(relation))),
-													  class_form->relrewrite ?
+													  OidIsValid(class_form->relrewrite) ?
 													  get_rel_name(class_form->relrewrite) :
 													  NameStr(class_form->relname)));
 	appendStringInfoChar(ctx->out, ':');
diff --git a/src/backend/access/heap/heaptoast.c b/src/backend/access/heap/heaptoast.c
index e148c9be482..23688f8937d 100644
--- a/src/backend/access/heap/heaptoast.c
+++ b/src/backend/access/heap/heaptoast.c
@@ -213,7 +213,7 @@ heap_toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup,
 		 * XXX maybe the threshold should be less than maxDataLen?
 		 */
 		if (toast_attr[biggest_attno].tai_size > maxDataLen &&
-			rel->rd_rel->reltoastrelid != InvalidOid)
+			OidIsValid(rel->rd_rel->reltoastrelid))
 			toast_tuple_externalize(&ttc, biggest_attno, options);
 	}
 
@@ -224,7 +224,7 @@ heap_toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup,
 	 */
 	while (heap_compute_data_size(tupleDesc,
 								  toast_values, toast_isnull) > maxDataLen &&
-		   rel->rd_rel->reltoastrelid != InvalidOid)
+		   OidIsValid(rel->rd_rel->reltoastrelid))
 	{
 		int			biggest_attno;
 
@@ -259,7 +259,7 @@ heap_toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup,
 
 	while (heap_compute_data_size(tupleDesc,
 								  toast_values, toast_isnull) > maxDataLen &&
-		   rel->rd_rel->reltoastrelid != InvalidOid)
+		   OidIsValid(rel->rd_rel->reltoastrelid))
 	{
 		int			biggest_attno;
 
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index 60b168e668c..2025a3ac2d2 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -551,7 +551,7 @@ DefineAttr(char *name, char *type, int attnum, int nullness)
 		attrtypes[attnum]->attcompression = InvalidCompressionMethod;
 		attrtypes[attnum]->attcollation = Ap->am_typ.typcollation;
 		/* if an array type, assume 1-dimensional attribute */
-		if (Ap->am_typ.typelem != InvalidOid && Ap->am_typ.typlen < 0)
+		if (OidIsValid(Ap->am_typ.typelem) && Ap->am_typ.typlen < 0)
 			attrtypes[attnum]->attndims = 1;
 		else
 			attrtypes[attnum]->attndims = 0;
diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c
index 9944e4bd2d1..5c21167a5a9 100644
--- a/src/backend/catalog/pg_constraint.c
+++ b/src/backend/catalog/pg_constraint.c
@@ -1127,7 +1127,7 @@ ConstraintSetParentConstraint(Oid childConstrId,
 	{
 		/* don't allow setting parent for a constraint that already has one */
 		Assert(constrForm->coninhcount == 0);
-		if (constrForm->conparentid != InvalidOid)
+		if (OidIsValid(constrForm->conparentid))
 			elog(ERROR, "constraint %u already has a parent constraint",
 				 childConstrId);
 
diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c
index 2f0f1ace7a3..ee76d23dd43 100644
--- a/src/backend/catalog/pg_shdepend.c
+++ b/src/backend/catalog/pg_shdepend.c
@@ -752,7 +752,7 @@ checkSharedDependencies(Oid classId, Oid objectId,
 		 * number of them later.
 		 */
 		if (sdepForm->dbid == MyDatabaseId ||
-			sdepForm->dbid == InvalidOid)
+			!OidIsValid(sdepForm->dbid))
 		{
 			if (numobjects >= allocedobjects)
 			{
@@ -1403,7 +1403,7 @@ shdepDropOwned(List *roleids, DropBehavior behavior)
 			 * database
 			 */
 			if (sdepForm->dbid != MyDatabaseId &&
-				sdepForm->dbid != InvalidOid)
+				OidIsValid(sdepForm->dbid))
 				continue;
 
 			switch (sdepForm->deptype)
@@ -1589,7 +1589,7 @@ shdepReassignOwned(List *roleids, Oid newrole)
 			 * database
 			 */
 			if (sdepForm->dbid != MyDatabaseId &&
-				sdepForm->dbid != InvalidOid)
+				OidIsValid(sdepForm->dbid))
 				continue;
 
 			/*
diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c
index e42bb2a2082..ed2e3a8592d 100644
--- a/src/backend/catalog/toasting.c
+++ b/src/backend/catalog/toasting.c
@@ -149,7 +149,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
 	/*
 	 * Is it already toasted?
 	 */
-	if (rel->rd_rel->reltoastrelid != InvalidOid)
+	if (OidIsValid(rel->rd_rel->reltoastrelid))
 		return false;
 
 	/*
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index d8990930145..3314b253352 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -874,7 +874,7 @@ copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldIndex, bool verb
 	 * We don't need to open the toast relation here, just lock it.  The lock
 	 * will be held till end of transaction.
 	 */
-	if (OldHeap->rd_rel->reltoastrelid)
+	if (OidIsValid(OldHeap->rd_rel->reltoastrelid))
 		LockRelationOid(OldHeap->rd_rel->reltoastrelid, AccessExclusiveLock);
 
 	/*
@@ -884,7 +884,7 @@ copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldIndex, bool verb
 	 * swap by links.  This is okay because swap by content is only essential
 	 * for system catalogs, and we don't support schema changes for them.
 	 */
-	if (OldHeap->rd_rel->reltoastrelid && NewHeap->rd_rel->reltoastrelid)
+	if (OidIsValid(OldHeap->rd_rel->reltoastrelid) && OidIsValid(NewHeap->rd_rel->reltoastrelid))
 	{
 		*pSwapToastByContent = true;
 
@@ -1158,7 +1158,7 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
 			elog(ERROR, "cannot change access method of mapped relation \"%s\"",
 				 NameStr(relform1->relname));
 		if (!swap_toast_by_content &&
-			(relform1->reltoastrelid || relform2->reltoastrelid))
+			(OidIsValid(relform1->reltoastrelid) || OidIsValid(relform2->reltoastrelid)))
 			elog(ERROR, "cannot swap toast by links for mapped relation \"%s\"",
 				 NameStr(relform1->relname));
 
@@ -1310,11 +1310,11 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
 	 * If we have toast tables associated with the relations being swapped,
 	 * deal with them too.
 	 */
-	if (relform1->reltoastrelid || relform2->reltoastrelid)
+	if (OidIsValid(relform1->reltoastrelid) || OidIsValid(relform2->reltoastrelid))
 	{
 		if (swap_toast_by_content)
 		{
-			if (relform1->reltoastrelid && relform2->reltoastrelid)
+			if (OidIsValid(relform1->reltoastrelid) && OidIsValid(relform2->reltoastrelid))
 			{
 				/* Recursively swap the contents of the toast tables */
 				swap_relation_files(relform1->reltoastrelid,
@@ -1359,7 +1359,7 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
 				elog(ERROR, "cannot swap toast files by links for system catalogs");
 
 			/* Delete old dependencies */
-			if (relform1->reltoastrelid)
+			if (OidIsValid(relform1->reltoastrelid))
 			{
 				count = deleteDependencyRecordsFor(RelationRelationId,
 												   relform1->reltoastrelid,
@@ -1368,7 +1368,7 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
 					elog(ERROR, "expected one dependency record for TOAST table, found %ld",
 						 count);
 			}
-			if (relform2->reltoastrelid)
+			if (OidIsValid(relform2->reltoastrelid))
 			{
 				count = deleteDependencyRecordsFor(RelationRelationId,
 												   relform2->reltoastrelid,
@@ -1384,7 +1384,7 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
 			toastobject.classId = RelationRelationId;
 			toastobject.objectSubId = 0;
 
-			if (relform1->reltoastrelid)
+			if (OidIsValid(relform1->reltoastrelid))
 			{
 				baseobject.objectId = r1;
 				toastobject.objectId = relform1->reltoastrelid;
@@ -1392,7 +1392,7 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
 								   DEPENDENCY_INTERNAL);
 			}
 
-			if (relform2->reltoastrelid)
+			if (OidIsValid(relform2->reltoastrelid))
 			{
 				baseobject.objectId = r2;
 				toastobject.objectId = relform2->reltoastrelid;
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 1118a5fc437..45bcfff23d6 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -3788,7 +3788,7 @@ renameatt_check(Oid myrelid, Form_pg_class classform, bool recursing)
 {
 	char		relkind = classform->relkind;
 
-	if (classform->reloftype && !recursing)
+	if (OidIsValid(classform->reloftype) && !recursing)
 		ereport(ERROR,
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("cannot rename column of typed table")));
@@ -4118,7 +4118,7 @@ rename_constraint_internal(Oid myrelid,
 							oldconname)));
 	}
 
-	if (con->conindid
+	if (OidIsValid(con->conindid)
 		&& (con->contype == CONSTRAINT_PRIMARY
 			|| con->contype == CONSTRAINT_UNIQUE
 			|| con->contype == CONSTRAINT_EXCLUSION))
@@ -7186,7 +7186,7 @@ ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
 				bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode,
 				AlterTableUtilityContext *context)
 {
-	if (rel->rd_rel->reloftype && !recursing)
+	if (OidIsValid(rel->rd_rel->reloftype) && !recursing)
 		ereport(ERROR,
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("cannot add column to typed table")));
@@ -9249,7 +9249,7 @@ ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
 				 AlterTableCmd *cmd, LOCKMODE lockmode,
 				 AlterTableUtilityContext *context)
 {
-	if (rel->rd_rel->reloftype && !recursing)
+	if (OidIsValid(rel->rd_rel->reloftype) && !recursing)
 		ereport(ERROR,
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("cannot drop column from typed table")));
@@ -14385,7 +14385,7 @@ ATPrepAlterColumnType(List **wqueue,
 
 	pstate->p_sourcetext = context->queryString;
 
-	if (rel->rd_rel->reloftype && !recursing)
+	if (OidIsValid(rel->rd_rel->reloftype) && !recursing)
 		ereport(ERROR,
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("cannot alter column type of typed table"),
@@ -16280,7 +16280,7 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lock
 		}
 
 		/* If it has a toast table, recurse to change its ownership */
-		if (tuple_class->reltoastrelid != InvalidOid)
+		if (OidIsValid(tuple_class->reltoastrelid))
 			ATExecChangeOwner(tuple_class->reltoastrelid, newOwnerId,
 							  true, lockmode);
 
@@ -17230,7 +17230,7 @@ ATExecEnableDisableRule(Relation rel, const char *rulename,
 static void
 ATPrepAddInherit(Relation child_rel)
 {
-	if (child_rel->rd_rel->reloftype)
+	if (OidIsValid(child_rel->rd_rel->reloftype))
 		ereport(ERROR,
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("cannot change inheritance of typed table")));
@@ -18307,7 +18307,7 @@ ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode)
 	}
 
 	/* If the table was already typed, drop the existing dependency. */
-	if (rel->rd_rel->reloftype)
+	if (OidIsValid(rel->rd_rel->reloftype))
 		drop_parent_dependency(relid, TypeRelationId, rel->rd_rel->reloftype,
 							   DEPENDENCY_NORMAL);
 
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 3c80bf1b9ce..6443b38586d 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -2541,7 +2541,7 @@ addRangeTableEntryForENR(ParseState *pstate,
 		else
 		{
 			/* Let's just make sure we can tell this isn't dropped */
-			if (att->atttypid == InvalidOid)
+			if (!OidIsValid(att->atttypid))
 				elog(ERROR, "atttypid is invalid for non-dropped column in \"%s\"",
 					 rv->relname);
 			rte->coltypes = lappend_oid(rte->coltypes, att->atttypid);
diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c
index c1c13f43918..875b3690f9b 100644
--- a/src/backend/replication/logical/reorderbuffer.c
+++ b/src/backend/replication/logical/reorderbuffer.c
@@ -2366,7 +2366,7 @@ ReorderBufferProcessTXN(ReorderBuffer *rb, ReorderBufferTXN *txn,
 					 * Ignore temporary heaps created during DDL unless the
 					 * plugin has asked for them.
 					 */
-					if (relation->rd_rel->relrewrite && !rb->output_rewrites)
+					if (OidIsValid(relation->rd_rel->relrewrite) && !rb->output_rewrites)
 						goto change_done;
 
 					/*
diff --git a/src/backend/utils/adt/dbsize.c b/src/backend/utils/adt/dbsize.c
index 894d226541f..09975724d96 100644
--- a/src/backend/utils/adt/dbsize.c
+++ b/src/backend/utils/adt/dbsize.c
@@ -908,7 +908,7 @@ pg_relation_filenode(PG_FUNCTION_ARGS)
 
 	if (RELKIND_HAS_STORAGE(relform->relkind))
 	{
-		if (relform->relfilenode)
+		if (OidIsValid(relform->relfilenode))
 			result = relform->relfilenode;
 		else					/* Consult the relation mapper */
 			result = RelationMapOidToFilenumber(relid,
@@ -986,7 +986,7 @@ pg_relation_filepath(PG_FUNCTION_ARGS)
 	if (RELKIND_HAS_STORAGE(relform->relkind))
 	{
 		/* This logic should match RelationInitPhysicalAddr */
-		if (relform->reltablespace)
+		if (OidIsValid(relform->reltablespace))
 			rlocator.spcOid = relform->reltablespace;
 		else
 			rlocator.spcOid = MyDatabaseTableSpace;
@@ -994,7 +994,7 @@ pg_relation_filepath(PG_FUNCTION_ARGS)
 			rlocator.dbOid = InvalidOid;
 		else
 			rlocator.dbOid = MyDatabaseId;
-		if (relform->relfilenode)
+		if (OidIsValid(relform->relfilenode))
 			rlocator.relNumber = relform->relfilenode;
 		else					/* Consult the relation mapper */
 			rlocator.relNumber = RelationMapOidToFilenumber(relid,
diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c
index 22b0319abdf..7ae1a85a5ab 100644
--- a/src/backend/utils/adt/regproc.c
+++ b/src/backend/utils/adt/regproc.c
@@ -760,7 +760,7 @@ format_operator_extended(Oid operator_oid, bits16 flags)
 
 		appendStringInfo(&buf, "%s(", oprname);
 
-		if (operform->oprleft)
+		if (OidIsValid(operform->oprleft))
 			appendStringInfo(&buf, "%s,",
 							 (flags & FORMAT_OPERATOR_FORCE_QUALIFY) != 0 ?
 							 format_type_be_qualified(operform->oprleft) :
@@ -768,7 +768,7 @@ format_operator_extended(Oid operator_oid, bits16 flags)
 		else
 			appendStringInfoString(&buf, "NONE,");
 
-		if (operform->oprright)
+		if (OidIsValid(operform->oprright))
 			appendStringInfo(&buf, "%s)",
 							 (flags & FORMAT_OPERATOR_FORCE_QUALIFY) != 0 ?
 							 format_type_be_qualified(operform->oprright) :
@@ -830,10 +830,10 @@ format_operator_parts(Oid operator_oid, List **objnames, List **objargs,
 	*objnames = list_make2(get_namespace_name_or_temp(oprForm->oprnamespace),
 						   pstrdup(NameStr(oprForm->oprname)));
 	*objargs = NIL;
-	if (oprForm->oprleft)
+	if (OidIsValid(oprForm->oprleft))
 		*objargs = lappend(*objargs,
 						   format_type_be_qualified(oprForm->oprleft));
-	if (oprForm->oprright)
+	if (OidIsValid(oprForm->oprright))
 		*objargs = lappend(*objargs,
 						   format_type_be_qualified(oprForm->oprright));
 
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 1e4f57bf245..c8ec2579d9a 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -2489,7 +2489,7 @@ pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
 				expr = stringToNode(conbin);
 
 				/* Set up deparsing context for Var nodes in constraint */
-				if (conForm->conrelid != InvalidOid)
+				if (OidIsValid(conForm->conrelid))
 				{
 					/* relation constraint */
 					context = deparse_context_for(get_relation_name(conForm->conrelid),
@@ -2523,7 +2523,7 @@ pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
 			}
 		case CONSTRAINT_NOTNULL:
 			{
-				if (conForm->conrelid)
+				if (OidIsValid(conForm->conrelid))
 				{
 					AttrNumber	attnum;
 
@@ -2535,7 +2535,7 @@ pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
 					if (((Form_pg_constraint) GETSTRUCT(tup))->connoinherit)
 						appendStringInfoString(&buf, " NO INHERIT");
 				}
-				else if (conForm->contypid)
+				else if (OidIsValid(conForm->contypid))
 				{
 					/* conkey is null for domain not-null constraints */
 					appendStringInfoString(&buf, "NOT NULL");
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 915d0bc9084..62fe96f32d0 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -535,7 +535,7 @@ RelationBuildTupleDesc(Relation relation)
 
 	/* fill rd_att's type ID fields (compare heap.c's AddNewRelationTuple) */
 	relation->rd_att->tdtypeid =
-		relation->rd_rel->reltype ? relation->rd_rel->reltype : RECORDOID;
+		OidIsValid(relation->rd_rel->reltype) ? relation->rd_rel->reltype : RECORDOID;
 	relation->rd_att->tdtypmod = -1;	/* just to be sure */
 
 	constr = (TupleConstr *) MemoryContextAllocZero(CacheMemoryContext,
@@ -1236,7 +1236,7 @@ retry:
 		 */
 	}
 	else
-		Assert(relation->rd_rel->relam == InvalidOid);
+		Assert(!OidIsValid(relation->rd_rel->relam));
 
 	/* extract reloptions if any */
 	RelationParseRelOptions(relation, pg_class_tuple);
@@ -1344,7 +1344,7 @@ RelationInitPhysicalAddr(Relation relation)
 	if (!RELKIND_HAS_STORAGE(relation->rd_rel->relkind))
 		return;
 
-	if (relation->rd_rel->reltablespace)
+	if (OidIsValid(relation->rd_rel->reltablespace))
 		relation->rd_locator.spcOid = relation->rd_rel->reltablespace;
 	else
 		relation->rd_locator.spcOid = MyDatabaseTableSpace;
@@ -1353,7 +1353,7 @@ RelationInitPhysicalAddr(Relation relation)
 	else
 		relation->rd_locator.dbOid = MyDatabaseId;
 
-	if (relation->rd_rel->relfilenode)
+	if (OidIsValid(relation->rd_rel->relfilenode))
 	{
 		/*
 		 * Even if we are using a decoding snapshot that doesn't represent the
@@ -1478,7 +1478,7 @@ RelationInitIndexAccessInfo(Relation relation)
 	/*
 	 * Look up the index's access method, save the OID of its handler function
 	 */
-	Assert(relation->rd_rel->relam != InvalidOid);
+	Assert(OidIsValid(relation->rd_rel->relam));
 	tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(relation->rd_rel->relam));
 	if (!HeapTupleIsValid(tuple))
 		elog(ERROR, "cache lookup failed for access method %u",
@@ -1838,7 +1838,7 @@ RelationInitTableAccessMethod(Relation relation)
 		 * seem prudent to show that in the catalog. So just overwrite it
 		 * here.
 		 */
-		Assert(relation->rd_rel->relam == InvalidOid);
+		Assert(!OidIsValid(relation->rd_rel->relam));
 		relation->rd_amhandler = F_HEAP_TABLEAM_HANDLER;
 	}
 	else if (IsCatalogRelation(relation))
@@ -1855,7 +1855,7 @@ RelationInitTableAccessMethod(Relation relation)
 		 * Look up the table access method, save the OID of its handler
 		 * function.
 		 */
-		Assert(relation->rd_rel->relam != InvalidOid);
+		Assert(OidIsValid(relation->rd_rel->relam));
 		tuple = SearchSysCache1(AMOID,
 								ObjectIdGetDatum(relation->rd_rel->relam));
 		if (!HeapTupleIsValid(tuple))
@@ -4259,7 +4259,7 @@ RelationCacheInitializePhase3(void)
 		/*
 		 * If it's a faked-up entry, read the real pg_class tuple.
 		 */
-		if (relation->rd_rel->relowner == InvalidOid)
+		if (!OidIsValid(relation->rd_rel->relowner))
 		{
 			HeapTuple	htup;
 			Form_pg_class relp;
@@ -4296,7 +4296,7 @@ RelationCacheInitializePhase3(void)
 			ReleaseSysCache(htup);
 
 			/* relowner had better be OK now, else we'll loop forever */
-			if (relation->rd_rel->relowner == InvalidOid)
+			if (!OidIsValid(relation->rd_rel->relowner))
 				elog(ERROR, "invalid relowner in pg_class entry for \"%s\"",
 					 RelationGetRelationName(relation));
 
@@ -6252,7 +6252,7 @@ load_relcache_init_file(bool shared)
 		rel->rd_att = CreateTemplateTupleDesc(relform->relnatts);
 		rel->rd_att->tdrefcount = 1;	/* mark as refcounted */
 
-		rel->rd_att->tdtypeid = relform->reltype ? relform->reltype : RECORDOID;
+		rel->rd_att->tdtypeid = OidIsValid(relform->reltype) ? relform->reltype : RECORDOID;
 		rel->rd_att->tdtypmod = -1; /* just to be sure */
 
 		/* next read all the attribute tuple form data entries */
-- 
2.34.1

v1-0005-Use-OidIsValid-in-various-places-for-functions-re.patchtext/x-diff; charset=us-asciiDownload
From 4a2cc9691d118d5ab128086e2832999574d33077 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Sun, 16 Nov 2025 07:12:10 +0000
Subject: [PATCH v1 5/8] Use OidIsValid() in various places for functions
 returning OID

Let's use OidIsValid() instead of:

- direct comparisons with InvalidOid
- direct comparisons with literal 0
---
 src/backend/catalog/index.c         | 2 +-
 src/backend/catalog/pg_conversion.c | 4 +---
 src/backend/catalog/pg_proc.c       | 2 +-
 src/backend/commands/extension.c    | 2 +-
 src/backend/commands/tablecmds.c    | 5 ++---
 src/backend/parser/parse_collate.c  | 4 ++--
 src/include/parser/parse_type.h     | 2 +-
 src/include/utils/lsyscache.h       | 4 ++--
 8 files changed, 11 insertions(+), 14 deletions(-)
  26.8% src/backend/catalog/
  26.8% src/backend/commands/
  16.8% src/backend/parser/
   9.4% src/include/parser/
  19.9% src/include/utils/

diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 120d7ad641c..a12c2d85e95 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -884,7 +884,7 @@ index_create(Relation heapRelation,
 	 * catalogs' unique indexes anyway, but we prefer to give a friendlier
 	 * error message.
 	 */
-	if (get_relname_relid(indexRelationName, namespaceId))
+	if (OidIsValid(get_relname_relid(indexRelationName, namespaceId)))
 	{
 		if ((flags & INDEX_CREATE_IF_NOT_EXISTS) != 0)
 		{
diff --git a/src/backend/catalog/pg_conversion.c b/src/backend/catalog/pg_conversion.c
index 090f680d190..b2b1b058a2a 100644
--- a/src/backend/catalog/pg_conversion.c
+++ b/src/backend/catalog/pg_conversion.c
@@ -69,9 +69,7 @@ ConversionCreate(const char *conname, Oid connamespace,
 		 * make sure there is no existing default <for encoding><to encoding>
 		 * pair in this name space
 		 */
-		if (FindDefaultConversion(connamespace,
-								  conforencoding,
-								  contoencoding))
+		if (OidIsValid(FindDefaultConversion(connamespace, conforencoding, contoencoding)))
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_OBJECT),
 					 errmsg("default conversion for %s to %s already exists",
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index b89b9ccda0e..a639d8ef762 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -765,7 +765,7 @@ fmgr_internal_validator(PG_FUNCTION_ARGS)
 	tmp = SysCacheGetAttrNotNull(PROCOID, tuple, Anum_pg_proc_prosrc);
 	prosrc = TextDatumGetCString(tmp);
 
-	if (fmgr_internal_function(prosrc) == InvalidOid)
+	if (!OidIsValid(fmgr_internal_function(prosrc)))
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_FUNCTION),
 				 errmsg("there is no built-in function named \"%s\"",
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 43a5642fd10..2c389cf6433 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -1981,7 +1981,7 @@ CreateExtension(ParseState *pstate, CreateExtensionStmt *stmt)
 	 * in case of race conditions; but this is a friendlier error message, and
 	 * besides we need a check to support IF NOT EXISTS.
 	 */
-	if (get_extension_oid(stmt->extname, true) != InvalidOid)
+	if (OidIsValid(get_extension_oid(stmt->extname, true)))
 	{
 		if (stmt->if_not_exists)
 		{
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 45bcfff23d6..0d335123b5b 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -4292,7 +4292,7 @@ RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bo
 	otid = reltup->t_self;
 	relform = (Form_pg_class) GETSTRUCT(reltup);
 
-	if (get_relname_relid(newrelname, namespaceId) != InvalidOid)
+	if (OidIsValid(get_relname_relid(newrelname, namespaceId)))
 		ereport(ERROR,
 				(errcode(ERRCODE_DUPLICATE_TABLE),
 				 errmsg("relation \"%s\" already exists",
@@ -19074,8 +19074,7 @@ AlterRelationNamespaceInternal(Relation classRel, Oid relOid,
 		ItemPointerData otid = classTup->t_self;
 
 		/* check for duplicate name (more friendly than unique-index failure) */
-		if (get_relname_relid(NameStr(classForm->relname),
-							  newNspOid) != InvalidOid)
+		if (OidIsValid(get_relname_relid(NameStr(classForm->relname), newNspOid)))
 			ereport(ERROR,
 					(errcode(ERRCODE_DUPLICATE_TABLE),
 					 errmsg("relation \"%s\" already exists in schema \"%s\"",
diff --git a/src/backend/parser/parse_collate.c b/src/backend/parser/parse_collate.c
index d2e218353f3..efb518679f0 100644
--- a/src/backend/parser/parse_collate.c
+++ b/src/backend/parser/parse_collate.c
@@ -924,7 +924,7 @@ assign_ordered_set_collations(Aggref *aggref,
 
 	/* Merge sort collations to parent only if there can be only one */
 	merge_sort_collations = (list_length(aggref->args) == 1 &&
-							 get_func_variadictype(aggref->aggfnoid) == InvalidOid);
+							 !OidIsValid(get_func_variadictype(aggref->aggfnoid)));
 
 	/* Direct args, if any, are normal children of the Aggref node */
 	(void) assign_collations_walker((Node *) aggref->aggdirectargs,
@@ -962,7 +962,7 @@ assign_hypothetical_collations(Aggref *aggref,
 
 	/* Merge sort collations to parent only if there can be only one */
 	merge_sort_collations = (list_length(aggref->args) == 1 &&
-							 get_func_variadictype(aggref->aggfnoid) == InvalidOid);
+							 !OidIsValid(get_func_variadictype(aggref->aggfnoid)));
 
 	/* Process any non-hypothetical direct args */
 	extra_args = list_length(aggref->aggdirectargs) - list_length(aggref->args);
diff --git a/src/include/parser/parse_type.h b/src/include/parser/parse_type.h
index 0d919d8bfa2..304b885db94 100644
--- a/src/include/parser/parse_type.h
+++ b/src/include/parser/parse_type.h
@@ -56,6 +56,6 @@ extern bool parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p,
 							Node *escontext);
 
 /* true if typeid is composite, or domain over composite, but not RECORD */
-#define ISCOMPLEX(typeid) (typeOrDomainTypeRelid(typeid) != InvalidOid)
+#define ISCOMPLEX(typeid) (OidIsValid(typeOrDomainTypeRelid(typeid)))
 
 #endif							/* PARSE_TYPE_H */
diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h
index 50fb149e9ac..dc2d69b6d4e 100644
--- a/src/include/utils/lsyscache.h
+++ b/src/include/utils/lsyscache.h
@@ -211,9 +211,9 @@ extern char *get_publication_name(Oid pubid, bool missing_ok);
 extern Oid	get_subscription_oid(const char *subname, bool missing_ok);
 extern char *get_subscription_name(Oid subid, bool missing_ok);
 
-#define type_is_array(typid)  (get_element_type(typid) != InvalidOid)
+#define type_is_array(typid)  (OidIsValid(get_element_type(typid)))
 /* type_is_array_domain accepts both plain arrays and domains over arrays */
-#define type_is_array_domain(typid)  (get_base_element_type(typid) != InvalidOid)
+#define type_is_array_domain(typid)  (OidIsValid(get_base_element_type(typid)))
 
 #define TypeIsToastable(typid)	(get_typstorage(typid) != TYPSTORAGE_PLAIN)
 
-- 
2.34.1

v1-0006-Use-OidIsValid-in-various-places-for-edge-cases.patchtext/x-diff; charset=us-asciiDownload
From d1b9e3bddd6939bfe64b0f4b486fd2caa4d30786 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Mon, 17 Nov 2025 09:07:52 +0000
Subject: [PATCH v1 6/8] Use OidIsValid() in various places for edge cases

Let's use OidIsValid() instead of:

- direct comparisons with InvalidOid
- direct comparisons with literal 0
---
 contrib/btree_gin/btree_gin.c         | 2 +-
 src/backend/commands/tablecmds.c      | 2 +-
 src/backend/optimizer/path/indxpath.c | 2 +-
 src/backend/partitioning/partprune.c  | 2 +-
 src/backend/utils/cache/inval.c       | 4 ++--
 src/include/replication/slot.h        | 4 ++--
 6 files changed, 8 insertions(+), 8 deletions(-)
  10.5% contrib/btree_gin/
  13.3% src/backend/commands/
  15.7% src/backend/optimizer/path/
  12.6% src/backend/partitioning/
  17.4% src/backend/utils/cache/
  30.1% src/include/replication/

diff --git a/contrib/btree_gin/btree_gin.c b/contrib/btree_gin/btree_gin.c
index 8c477d17e22..03c49a61fe5 100644
--- a/contrib/btree_gin/btree_gin.c
+++ b/contrib/btree_gin/btree_gin.c
@@ -857,7 +857,7 @@ GIN_SUPPORT(numeric, leftmostvalue_numeric, numeric_rhs_is_varlena, NULL, numeri
  * routines it needs it, so we can't use DirectFunctionCall2.
  */
 
-#define ENUM_IS_LEFTMOST(x) ((x) == InvalidOid)
+#define ENUM_IS_LEFTMOST(x) !OidIsValid(x)
 
 PG_FUNCTION_INFO_V1(gin_enum_cmp);
 
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 0d335123b5b..f4e9490cd71 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -19223,7 +19223,7 @@ AlterSeqNamespaces(Relation classRel, Relation rel,
 		 * ever re-instate that, we'll need to move the pg_type entry to the
 		 * new namespace, too (using AlterTypeNamespaceInternal).
 		 */
-		Assert(RelationGetForm(seqRel)->reltype == InvalidOid);
+		Assert(!OidIsValid(RelationGetForm(seqRel)->reltype));
 
 		/* Now we can close it.  Keep the lock till end of transaction. */
 		relation_close(seqRel, NoLock);
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 62a6642222b..932ffa75745 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -40,7 +40,7 @@
 
 /* XXX see PartCollMatchesExprColl */
 #define IndexCollMatchesExprColl(idxcollation, exprcollation) \
-	((idxcollation) == InvalidOid || (idxcollation) == (exprcollation))
+	(!OidIsValid(idxcollation) || (idxcollation) == (exprcollation))
 
 /* Whether we are looking for plain indexscan, bitmap scan, or either */
 typedef enum
diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c
index 6fff4034c24..ec9582b1b1d 100644
--- a/src/backend/partitioning/partprune.c
+++ b/src/backend/partitioning/partprune.c
@@ -1782,7 +1782,7 @@ gen_prune_steps_from_opexps(GeneratePruningStepsContext *context,
  * See also IndexCollMatchesExprColl.
  */
 #define PartCollMatchesExprColl(partcoll, exprcoll) \
-	((partcoll) == InvalidOid || (partcoll) == (exprcoll))
+	(!OidIsValid(partcoll) || (partcoll) == (exprcoll))
 
 /*
  * match_clause_to_partition_key
diff --git a/src/backend/utils/cache/inval.c b/src/backend/utils/cache/inval.c
index 25893fc0d78..4220a51c464 100644
--- a/src/backend/utils/cache/inval.c
+++ b/src/backend/utils/cache/inval.c
@@ -481,7 +481,7 @@ AddRelcacheInvalidationMessage(InvalidationMsgsGroup *group,
 	ProcessMessageSubGroup(group, RelCacheMsgs,
 						   if (msg->rc.id == SHAREDINVALRELCACHE_ID &&
 							   (msg->rc.relId == relId ||
-								msg->rc.relId == InvalidOid))
+								!OidIsValid(msg->rc.relId)))
 						   return);
 
 	/* OK, add the item */
@@ -511,7 +511,7 @@ AddRelsyncInvalidationMessage(InvalidationMsgsGroup *group,
 	ProcessMessageSubGroup(group, RelCacheMsgs,
 						   if (msg->rc.id == SHAREDINVALRELSYNC_ID &&
 							   (msg->rc.relId == relId ||
-								msg->rc.relId == InvalidOid))
+								!OidIsValid(msg->rc.relId)))
 						   return);
 
 	/* OK, add the item */
diff --git a/src/include/replication/slot.h b/src/include/replication/slot.h
index 09c69f83d57..01b1c5097a4 100644
--- a/src/include/replication/slot.h
+++ b/src/include/replication/slot.h
@@ -251,8 +251,8 @@ typedef struct ReplicationSlot
 
 } ReplicationSlot;
 
-#define SlotIsPhysical(slot) ((slot)->data.database == InvalidOid)
-#define SlotIsLogical(slot) ((slot)->data.database != InvalidOid)
+#define SlotIsPhysical(slot) (!OidIsValid((slot)->data.database))
+#define SlotIsLogical(slot) (OidIsValid((slot)->data.database))
 
 /*
  * Shared memory control area for all of replication slots.
-- 
2.34.1

v1-0007-Replace-ternary-operators-with-OidIsValid.patchtext/x-diff; charset=us-asciiDownload
From a45ff8e15bf246ffc381648877651c21fef015a4 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Mon, 17 Nov 2025 09:21:20 +0000
Subject: [PATCH v1 7/8] Replace ternary operators with !OidIsValid()

And negated OidIsValid equality to use positive logic.
---
 src/backend/commands/tablecmds.c          |  4 ++--
 src/backend/nodes/nodeFuncs.c             |  4 ++--
 src/backend/utils/cache/plancache.c       | 12 ++++++------
 src/backend/utils/misc/queryenvironment.c |  2 +-
 4 files changed, 11 insertions(+), 11 deletions(-)
  19.1% src/backend/commands/
  11.2% src/backend/nodes/
  57.8% src/backend/utils/cache/
  11.6% src/backend/utils/misc/

diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index f4e9490cd71..60d9462038b 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -17112,8 +17112,8 @@ AlterTableMoveAll(AlterTableMoveAllStmt *stmt)
 		ereport(NOTICE,
 				(errcode(ERRCODE_NO_DATA_FOUND),
 				 errmsg("no matching relations in tablespace \"%s\" found",
-						!OidIsValid(orig_tablespaceoid) ? "(database default)" :
-						get_tablespace_name(orig_tablespaceoid))));
+						OidIsValid(orig_tablespaceoid) ? get_tablespace_name(orig_tablespaceoid) :
+						"(database default)")));
 
 	/* Everything is locked, loop through and move all of the relations. */
 	foreach(l, relations)
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index 5b11184bd0b..4a390e8821d 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -1241,12 +1241,12 @@ exprSetCollation(Node *expr, Oid collation)
 		case T_SQLValueFunction:
 			Assert((((SQLValueFunction *) expr)->type == NAMEOID) ?
 				   (collation == C_COLLATION_OID) :
-				   (!OidIsValid(collation)));
+				   !OidIsValid(collation));
 			break;
 		case T_XmlExpr:
 			Assert((((XmlExpr *) expr)->op == IS_XMLSERIALIZE) ?
 				   (collation == DEFAULT_COLLATION_OID) :
-				   (!OidIsValid(collation)));
+				   !OidIsValid(collation));
 			break;
 		case T_JsonValueExpr:
 			exprSetCollation((Node *) ((JsonValueExpr *) expr)->formatted_expr,
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index 54772e6c260..6d2ac455b74 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -2140,8 +2140,8 @@ PlanCacheRelCallback(Datum arg, Oid relid)
 		/*
 		 * Check the dependency list for the rewritten querytree.
 		 */
-		if ((!OidIsValid(relid)) ? plansource->relationOids != NIL :
-			list_member_oid(plansource->relationOids, relid))
+		if (OidIsValid(relid) ? list_member_oid(plansource->relationOids, relid) :
+			plansource->relationOids != NIL)
 		{
 			/* Invalidate the querytree and generic plan */
 			plansource->is_valid = false;
@@ -2163,8 +2163,8 @@ PlanCacheRelCallback(Datum arg, Oid relid)
 
 				if (plannedstmt->commandType == CMD_UTILITY)
 					continue;	/* Ignore utility statements */
-				if ((!OidIsValid(relid)) ? plannedstmt->relationOids != NIL :
-					list_member_oid(plannedstmt->relationOids, relid))
+				if (OidIsValid(relid) ? list_member_oid(plannedstmt->relationOids, relid) :
+					plannedstmt->relationOids != NIL)
 				{
 					/* Invalidate the generic plan only */
 					plansource->gplan->is_valid = false;
@@ -2186,8 +2186,8 @@ PlanCacheRelCallback(Datum arg, Oid relid)
 		if (!cexpr->is_valid)
 			continue;
 
-		if ((!OidIsValid(relid)) ? cexpr->relationOids != NIL :
-			list_member_oid(cexpr->relationOids, relid))
+		if (OidIsValid(relid) ? list_member_oid(cexpr->relationOids, relid) :
+			cexpr->relationOids != NIL)
 		{
 			cexpr->is_valid = false;
 		}
diff --git a/src/backend/utils/misc/queryenvironment.c b/src/backend/utils/misc/queryenvironment.c
index 8ae1783bc0e..001a6032645 100644
--- a/src/backend/utils/misc/queryenvironment.c
+++ b/src/backend/utils/misc/queryenvironment.c
@@ -127,7 +127,7 @@ ENRMetadataGetTupDesc(EphemeralNamedRelationMetadata enrmd)
 	TupleDesc	tupdesc;
 
 	/* One, and only one, of these fields must be filled. */
-	Assert((!OidIsValid(enrmd->reliddesc)) != (enrmd->tupdesc == NULL));
+	Assert(OidIsValid(enrmd->reliddesc) == (enrmd->tupdesc == NULL));
 
 	if (enrmd->tupdesc != NULL)
 		tupdesc = enrmd->tupdesc;
-- 
2.34.1

v1-0008-Replace-literal-0-with-InvalidOid-for-Oid-assignm.patchtext/x-diff; charset=us-asciiDownload
From 14fd765f7dfaf48fb94fcb127075bcbb9d995c01 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Mon, 17 Nov 2025 18:10:00 +0000
Subject: [PATCH v1 8/8] Replace literal 0 with InvalidOid for Oid assignments

Use the proper constant InvalidOid instead of literal 0 when assigning Oid
variables and struct fields.

This improves code clarity by making it explicit that these are invalid Oid
values rather than ambiguous zero literals.
---
 contrib/postgres_fdw/deparse.c             |  2 +-
 src/backend/access/common/printtup.c       |  2 +-
 src/backend/commands/extension.c           |  2 +-
 src/backend/storage/smgr/md.c              |  2 +-
 src/backend/utils/adt/like_support.c       |  2 +-
 src/backend/utils/cache/relfilenumbermap.c |  2 +-
 src/bin/pg_dump/common.c                   | 12 ++++++------
 src/bin/pg_dump/pg_dump.c                  |  8 ++++----
 src/bin/pg_resetwal/pg_resetwal.c          |  2 +-
 src/bin/pg_rewind/filemap.c                |  2 +-
 10 files changed, 18 insertions(+), 18 deletions(-)
   4.3% contrib/postgres_fdw/
   3.8% src/backend/access/common/
   4.6% src/backend/commands/
   4.3% src/backend/storage/smgr/
   6.4% src/backend/utils/adt/
   4.1% src/backend/utils/cache/
  63.2% src/bin/pg_dump/
   4.6% src/bin/pg_resetwal/
   4.3% src/bin/pg_rewind/

diff --git a/contrib/postgres_fdw/deparse.c b/contrib/postgres_fdw/deparse.c
index f2b8968c189..22546e0eae7 100644
--- a/contrib/postgres_fdw/deparse.c
+++ b/contrib/postgres_fdw/deparse.c
@@ -2727,7 +2727,7 @@ deparseColumnRef(StringInfo buf, int varno, int varattno, RangeTblEntry *rte,
 		 * careful; the table could be beneath an outer join, in which case it
 		 * must go to NULL whenever the rest of the row does.
 		 */
-		Oid			fetchval = 0;
+		Oid			fetchval = InvalidOid;
 
 		if (varattno == TableOidAttributeNumber)
 			fetchval = rte->relid;
diff --git a/src/backend/access/common/printtup.c b/src/backend/access/common/printtup.c
index 9f05e1d15bd..6734db55226 100644
--- a/src/backend/access/common/printtup.c
+++ b/src/backend/access/common/printtup.c
@@ -223,7 +223,7 @@ SendRowDescriptionMessage(StringInfo buf, TupleDesc typeinfo,
 		else
 		{
 			/* No info available, so send zeroes */
-			resorigtbl = 0;
+			resorigtbl = InvalidOid;
 			resorigcol = 0;
 		}
 
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 2c389cf6433..96fd63b628d 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -1072,7 +1072,7 @@ execute_extension_script(Oid extensionOid, ExtensionControlFile *control,
 {
 	bool		switch_to_superuser = false;
 	char	   *filename;
-	Oid			save_userid = 0;
+	Oid			save_userid = InvalidOid;
 	int			save_sec_context = 0;
 	int			save_nestlevel;
 	StringInfoData pathbuf;
diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c
index e3f335a8340..147f168abf3 100644
--- a/src/backend/storage/smgr/md.c
+++ b/src/backend/storage/smgr/md.c
@@ -1582,7 +1582,7 @@ ForgetDatabaseSyncRequests(Oid dbid)
 	RelFileLocator rlocator;
 
 	rlocator.dbOid = dbid;
-	rlocator.spcOid = 0;
+	rlocator.spcOid = InvalidOid;
 	rlocator.relNumber = 0;
 
 	INIT_MD_FILETAG(tag, rlocator, InvalidForkNumber, InvalidBlockNumber);
diff --git a/src/backend/utils/adt/like_support.c b/src/backend/utils/adt/like_support.c
index 5dbb2f57b4b..94c9504ba73 100644
--- a/src/backend/utils/adt/like_support.c
+++ b/src/backend/utils/adt/like_support.c
@@ -1594,7 +1594,7 @@ make_greater_string(const Const *str_const, FmgrInfo *ltproc, Oid collation)
 		{
 			/* If first time through, determine the suffix to use */
 			static char suffixchar = 0;
-			static Oid	suffixcollation = 0;
+			static Oid	suffixcollation = InvalidOid;
 
 			if (!suffixchar || suffixcollation != collation)
 			{
diff --git a/src/backend/utils/cache/relfilenumbermap.c b/src/backend/utils/cache/relfilenumbermap.c
index 3abd6f03282..1c9463c451d 100644
--- a/src/backend/utils/cache/relfilenumbermap.c
+++ b/src/backend/utils/cache/relfilenumbermap.c
@@ -153,7 +153,7 @@ RelidByRelfilenumber(Oid reltablespace, RelFileNumber relfilenumber)
 
 	/* pg_class will show 0 when the value is actually MyDatabaseTableSpace */
 	if (reltablespace == MyDatabaseTableSpace)
-		reltablespace = 0;
+		reltablespace = InvalidOid;
 
 	MemSet(&key, 0, sizeof(key));
 	key.reltablespace = reltablespace;
diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c
index bc1d3a7adc8..84591220122 100644
--- a/src/bin/pg_dump/common.c
+++ b/src/bin/pg_dump/common.c
@@ -355,8 +355,8 @@ flagInhTables(Archive *fout, TableInfo *tblinfo, int numTables,
 
 			attachinfo = (TableAttachInfo *) palloc(sizeof(TableAttachInfo));
 			attachinfo->dobj.objType = DO_TABLE_ATTACH;
-			attachinfo->dobj.catId.tableoid = 0;
-			attachinfo->dobj.catId.oid = 0;
+			attachinfo->dobj.catId.tableoid = InvalidOid;
+			attachinfo->dobj.catId.oid = InvalidOid;
 			AssignDumpId(&attachinfo->dobj);
 			attachinfo->dobj.name = pg_strdup(tblinfo[i].dobj.name);
 			attachinfo->dobj.namespace = tblinfo[i].dobj.namespace;
@@ -412,8 +412,8 @@ flagInhIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
 			attachinfo = pg_malloc_object(IndexAttachInfo);
 
 			attachinfo->dobj.objType = DO_INDEX_ATTACH;
-			attachinfo->dobj.catId.tableoid = 0;
-			attachinfo->dobj.catId.oid = 0;
+			attachinfo->dobj.catId.tableoid = InvalidOid;
+			attachinfo->dobj.catId.oid = InvalidOid;
 			AssignDumpId(&attachinfo->dobj);
 			attachinfo->dobj.name = pg_strdup(index->dobj.name);
 			attachinfo->dobj.namespace = index->indextable->dobj.namespace;
@@ -608,8 +608,8 @@ flagInhAttrs(Archive *fout, DumpOptions *dopt, TableInfo *tblinfo, int numTables
 
 				attrDef = pg_malloc_object(AttrDefInfo);
 				attrDef->dobj.objType = DO_ATTRDEF;
-				attrDef->dobj.catId.tableoid = 0;
-				attrDef->dobj.catId.oid = 0;
+				attrDef->dobj.catId.tableoid = InvalidOid;
+				attrDef->dobj.catId.oid = InvalidOid;
 				AssignDumpId(&attrDef->dobj);
 				attrDef->dobj.name = pg_strdup(tbinfo->dobj.name);
 				attrDef->dobj.namespace = tbinfo->dobj.namespace;
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 8be4714cd4b..20b3e29b5e9 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -3070,7 +3070,7 @@ makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
 	 * Note: use tableoid 0 so that this object won't be mistaken for
 	 * something that pg_depend entries apply to.
 	 */
-	tdinfo->dobj.catId.tableoid = 0;
+	tdinfo->dobj.catId.tableoid = InvalidOid;
 	tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
 	AssignDumpId(&tdinfo->dobj);
 	tdinfo->dobj.name = tbinfo->dobj.name;
@@ -4297,7 +4297,7 @@ getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
 			 */
 			polinfo = pg_malloc(sizeof(PolicyInfo));
 			polinfo->dobj.objType = DO_POLICY;
-			polinfo->dobj.catId.tableoid = 0;
+			polinfo->dobj.catId.tableoid = InvalidOid;
 			polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
 			AssignDumpId(&polinfo->dobj);
 			polinfo->dobj.namespace = tbinfo->dobj.namespace;
@@ -7110,8 +7110,8 @@ getRelationStatistics(Archive *fout, DumpableObject *rel, int32 relpages,
 		DumpableObject *dobj = &info->dobj;
 
 		dobj->objType = DO_REL_STATS;
-		dobj->catId.tableoid = 0;
-		dobj->catId.oid = 0;
+		dobj->catId.tableoid = InvalidOid;
+		dobj->catId.oid = InvalidOid;
 		AssignDumpId(dobj);
 		dobj->dependencies = (DumpId *) pg_malloc(sizeof(DumpId));
 		dobj->dependencies[0] = rel->dumpId;
diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c
index ebdbffc1336..c30a6c95741 100644
--- a/src/bin/pg_resetwal/pg_resetwal.c
+++ b/src/bin/pg_resetwal/pg_resetwal.c
@@ -69,7 +69,7 @@ static TransactionId set_oldest_xid = 0;
 static TransactionId set_xid = 0;
 static TransactionId set_oldest_commit_ts_xid = 0;
 static TransactionId set_newest_commit_ts_xid = 0;
-static Oid	set_oid = 0;
+static Oid	set_oid = InvalidOid;
 static bool mxid_given = false;
 static MultiXactId set_mxid = 0;
 static bool mxoff_given = false;
diff --git a/src/bin/pg_rewind/filemap.c b/src/bin/pg_rewind/filemap.c
index 467fd97ebcf..a400d487c59 100644
--- a/src/bin/pg_rewind/filemap.c
+++ b/src/bin/pg_rewind/filemap.c
@@ -619,7 +619,7 @@ getFileContentType(const char *path)
 	if (nmatch == 1 || nmatch == 2)
 	{
 		rlocator.spcOid = GLOBALTABLESPACE_OID;
-		rlocator.dbOid = 0;
+		rlocator.dbOid = InvalidOid;
 		result = FILE_CONTENT_TYPE_RELATION;
 	}
 	else
-- 
2.34.1

#34Peter Eisentraut
peter@eisentraut.org
In reply to: Bertrand Drouvot (#33)
Re: Consistently use the XLogRecPtrIsInvalid() macro

On 18.11.25 10:06, Bertrand Drouvot wrote:

Hi,

On Fri, Nov 07, 2025 at 03:03:03PM +0000, Bertrand Drouvot wrote:

I'm currently working on the RegProcedureIsValid() and OidIsValid() cases,
will share once done.

here they are, I'm not creating a new thread for those as this is the same
kind of ideas (but for other types) but can create a dedicated one if you prefer.

I don't like this change.

RegProcedureIsValid() doesn't add any value over OidIsValid, and we
don't have any RegXXXIsValid() for any of the other regxxx types. So if
we were to do anything about this, I would just remove it.

For OidIsValid etc., I don't think this improves the notation. It is
well understood that InvalidOid is 0. I mean, some people like writing
if (!foo) and some like writing if (foo == NULL), but we're not going to
legislate one over the other. But we're certainly not going to
introduce, uh, if (PointerIsValid(foo)), and in fact we just removed
that! What you're proposing here seem quite analogous but in the
opposite direction.

#35Bertrand Drouvot
bertranddrouvot.pg@gmail.com
In reply to: Peter Eisentraut (#34)
Re: Consistently use the XLogRecPtrIsInvalid() macro

Hi,

On Tue, Nov 18, 2025 at 04:54:32PM +0100, Peter Eisentraut wrote:

RegProcedureIsValid() doesn't add any value over OidIsValid, and we don't
have any RegXXXIsValid() for any of the other regxxx types. So if we were
to do anything about this, I would just remove it.

The patch makes use of it because it exists. I agree that we could also remove
it (for the reasons you mentioned above), I'll do that.

For OidIsValid etc., I don't think this improves the notation. It is well
understood that InvalidOid is 0.

I agree and that's perfectly valid to use 0 (unless InvalidOid does not mean
0 anymore in the future for whatever reasons). That said I think that using
the macro makes the code more consistent (same spirit as a2b02293bc6).

I mean, some people like writing if (!foo)
and some like writing if (foo == NULL), but we're not going to legislate one
over the other.

From that example, I understand that foo is a pointer.
I'am not sure that's a fair comparison with what this patch is doing. In your
example both are valids and not linked to any hardcoded value we set in the
code tree (as opposed to InvalidOid = 0).

But we're certainly not going to introduce, uh, if
(PointerIsValid(foo)), and in fact we just removed that!

I agree and I don't think the patch does that. It does not handle pointer implicit
comparisons (if it does in some places, that's a mistake).

What it does, is that when we have if (foo) and foo is an Oid (not a pointer to
an Oid) then change to if (OidIsValid(foo)).

So, instead of treating Oid values as booleans, the patch makes use of OidIsValid(),
which makes the intent clear: I'm checking if this Oid is valid, not "I'm checking
if this integer is non zero."

What you're
proposing here seem quite analogous but in the opposite direction.

I agree with the pointer case and I'll double check there is no such changes.

To clarify what the patches do, the transformations are (for var of type Oid):

- var != InvalidOid -> OidIsValid(var)
- var == InvalidOid -> !OidIsValid(var)
- var != 0 -> OidIsValid(var) (only when var is Oid, not pointer)
- var == 0 -> OidIsValid(var) (only when var is Oid, not pointer)
- var = 0 -> var = InvalidOid

The above is same idea as a2b02293bc6.

The one case I want to double check is transformations like:
if (tab->newTableSpace) -> if (OidIsValid(tab->newTableSpace))

Here, tab is a pointer to a struct, but newTableSpace is an Oid field. The
original code treats the Oid as a boolean. This is not a pointer validity check,
it's checking if the Oid value is non zero.

Do you consider this acceptable?

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

#36Álvaro Herrera
alvherre@kurilemu.de
In reply to: Bertrand Drouvot (#35)
Re: Consistently use the XLogRecPtrIsInvalid() macro

On 2025-Nov-18, Bertrand Drouvot wrote:

Hi,

On Tue, Nov 18, 2025 at 04:54:32PM +0100, Peter Eisentraut wrote:

RegProcedureIsValid() doesn't add any value over OidIsValid, and we
don't have any RegXXXIsValid() for any of the other regxxx types.
So if we were to do anything about this, I would just remove it.

The patch makes use of it because it exists. I agree that we could
also remove it (for the reasons you mentioned above), I'll do that.

RegProcedure actually predates all of our reg* types -- it goes back to
the initial commit of Postgres in 1989, according to
https://github.com/kelvich/postgres_pre95/commit/c4af0cb9d2a391815eb513416d95d49760202a42#diff-843ff64714a2c04906cdc890ccf6aedd0444e395e4ec412e70465638e80b2011R182

+/*
+ * RegProcedureIsValid
+ */
+bool
+RegProcedureIsValid(procedure)
+   RegProcedure    procedure;
+{
+   return (ObjectIdIsValid(procedure));
+}

I'm not sure what to think now about this whole idea of removing it.
Maybe there's some documentation value in it -- that line is saying,
this is not just any Oid, it's the Oid of a procedure. Is this
completely useless?

For OidIsValid etc., I don't think this improves the notation. It
is well understood that InvalidOid is 0.

I agree and that's perfectly valid to use 0 (unless InvalidOid does not mean
0 anymore in the future for whatever reasons). That said I think that using
the macro makes the code more consistent (same spirit as a2b02293bc6).

Well, what we were trying to do there was get rid of
XLogRecPtrIsInvalid(), which was clearly going against the grain re.
other IsValid macros. We got rid of the comparisons with 0 and
InvalidXLogRecPtr as a secondary effect, but that wasn't the main point.
This new patch series is much noisier and it's not at all clear to me
that we're achieving anything very useful. In fact, looking at proposed
changes, I would argue that there are several places that end up worse.

Honestly I'd leave this alone.

--
Álvaro Herrera Breisgau, Deutschland — https://www.EnterpriseDB.com/
"Ellos andaban todos desnudos como su madre los parió, y también las mujeres,
aunque no vi más que una, harto moza, y todos los que yo vi eran todos
mancebos, que ninguno vi de edad de más de XXX años" (Cristóbal Colón)

#37Bertrand Drouvot
bertranddrouvot.pg@gmail.com
In reply to: Álvaro Herrera (#36)
Re: Consistently use the XLogRecPtrIsInvalid() macro

Hi,

On Tue, Nov 18, 2025 at 06:57:33PM +0100, �lvaro Herrera wrote:

On 2025-Nov-18, Bertrand Drouvot wrote:

The patch makes use of it because it exists. I agree that we could
also remove it (for the reasons you mentioned above), I'll do that.

RegProcedure actually predates all of our reg* types -- it goes back to
the initial commit of Postgres in 1989, according to
https://github.com/kelvich/postgres_pre95/commit/c4af0cb9d2a391815eb513416d95d49760202a42#diff-843ff64714a2c04906cdc890ccf6aedd0444e395e4ec412e70465638e80b2011R182

Thanks for the info!

+/*
+ * RegProcedureIsValid
+ */
+bool
+RegProcedureIsValid(procedure)
+   RegProcedure    procedure;
+{
+   return (ObjectIdIsValid(procedure));
+}

I'm not sure what to think now about this whole idea of removing it.
Maybe there's some documentation value in it -- that line is saying,
this is not just any Oid, it's the Oid of a procedure. Is this
completely useless?

If it's not consistently used where it should be, and we're comparing against
InvalidOid instead, then I think that it looks useless. But if we ensure it's
used consistently throughout the codebase, then there is value in it.

Looking at 0001, it's not used for function calls in ginutil.c, not used
for boolean comparisons in plancat.c and selfuncs.c, and not used for variables
in regproc.c. I agree that the function calls and boolean comparisons changes
may look too noisy, but what about doing the regproc.c changes then and keep
RegProcedureIsValid()?

I agree and that's perfectly valid to use 0 (unless InvalidOid does not mean
0 anymore in the future for whatever reasons). That said I think that using
the macro makes the code more consistent (same spirit as a2b02293bc6).

Well, what we were trying to do there was get rid of
XLogRecPtrIsInvalid(), which was clearly going against the grain re.
other IsValid macros.

Right.

We got rid of the comparisons with 0 and
InvalidXLogRecPtr as a secondary effect, but that wasn't the main point.

I agree, but I think that was a good thing to do. I mean, ensuring the macro is
used sounds right. If not, what's the point of having the macro?

This new patch series is much noisier and it's not at all clear to me
that we're achieving anything very useful. In fact, looking at proposed
changes, I would argue that there are several places that end up worse.

Yeah, that's a lot of changes and maybe some of them are too noisy (like the ones
involving function calls). Maybe we could filter out what seems worth changing?

Keep those changes (for variables only):

- var != InvalidOid -> OidIsValid(var)
- var == InvalidOid -> !OidIsValid(var)

That would mean excluding the current 0 comparisons changes, but I'm not sure
that's fine, see [1]/messages/by-id/CACJufxGmsphWX150CxMU6KSed-x2fmTH3UpCwHpedGmjV1Biug@mail.gmail.com for other type example.

and maybe:

- var = 0 -> var = InvalidOid (when var is Oid)

I think that for variables only (i.e excluding function calls and implicit boolean
comparisons) that would be easier to read and less noisy. Worth a try to see what
it would look like?

[1]: /messages/by-id/CACJufxGmsphWX150CxMU6KSed-x2fmTH3UpCwHpedGmjV1Biug@mail.gmail.com

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

#38Robert Haas
robertmhaas@gmail.com
In reply to: Álvaro Herrera (#20)
Re: Consistently use the XLogRecPtrIsInvalid() macro

On Thu, Nov 6, 2025 at 2:48 PM Álvaro Herrera <alvherre@kurilemu.de> wrote:

Okay, thanks, I have applied that one to all stable branches, except I
didn't add the judgemental comment about XLogRecPtrIsInvalid().

I'm rather late to the party here, but for what it's worth, I don't
really think this was a good idea. Anyone who wants to write
out-of-core code that works in the back-branches must still write it
the old way, or it will potentially fail on older minor releases. Over
the alternative actually chosen, I would have preferred (a) not doing
this project at all or (b) making a hard switch in master to use the
new macro everywhere and remove the old one, while leaving the
back-branches unchanged or (c) dropping the use of the macro
altogether, in that order of preference.

That sad, I'm not arguing for a revert. My basic position is that this
wasn't worth the switching cost, not that it was intrinsically a bad
idea.

--
Robert Haas
EDB: http://www.enterprisedb.com

#39Álvaro Herrera
alvherre@kurilemu.de
In reply to: Robert Haas (#38)
Re: Consistently use the XLogRecPtrIsInvalid() macro

On 2025-Nov-19, Robert Haas wrote:

On Thu, Nov 6, 2025 at 2:48 PM Álvaro Herrera <alvherre@kurilemu.de> wrote:

Okay, thanks, I have applied that one to all stable branches, except
I didn't add the judgemental comment about XLogRecPtrIsInvalid().

I'm rather late to the party here, but for what it's worth, I don't
really think this was a good idea. Anyone who wants to write
out-of-core code that works in the back-branches must still write it
the old way, or it will potentially fail on older minor releases.

No, they don't need to. Thus far, they can still keep their code the
way it is. The next patch in the series (not yet committed, but I
intend to get it out at some point, unless there are objections) is
going to add an obsolescence warning when their code is compiled with
Postgres 21 -- by which time the minors without the new macro are going
to be two years old. Nobody needs to compile their code with minor
releases that old. So they can fix their code to work with Postgres 21
and with all contemporary minors. They don't need to ensure that their
code compiles with minors older than that.

We could make that Postgres 22, but I don't think that makes any
practical difference.

Maybe you misunderstood what the patch is doing.

--
Álvaro Herrera Breisgau, Deutschland — https://www.EnterpriseDB.com/

#40Robert Haas
robertmhaas@gmail.com
In reply to: Álvaro Herrera (#39)
Re: Consistently use the XLogRecPtrIsInvalid() macro

On Wed, Nov 19, 2025 at 11:49 AM Álvaro Herrera <alvherre@kurilemu.de> wrote:

I'm rather late to the party here, but for what it's worth, I don't
really think this was a good idea. Anyone who wants to write
out-of-core code that works in the back-branches must still write it
the old way, or it will potentially fail on older minor releases.

No, they don't need to. Thus far, they can still keep their code the
way it is.

True, but if they write any new code, and care about it compiling with
older minor releases, this is a potential pitfall.

The next patch in the series (not yet committed, but I
intend to get it out at some point, unless there are objections) is
going to add an obsolescence warning when their code is compiled with
Postgres 21 -- by which time the minors without the new macro are going
to be two years old. Nobody needs to compile their code with minor
releases that old. So they can fix their code to work with Postgres 21
and with all contemporary minors. They don't need to ensure that their
code compiles with minors older than that.

Well, if nobody needs to do this, then there's no problem, of course.
I doubt that's true, though.

We could make that Postgres 22, but I don't think that makes any
practical difference.

Maybe you misunderstood what the patch is doing.

It's possible, but fundamentally I think it's about replacing
XLogRecPtrIsInvalid with XLogRecPtrIsValid, and what I'm saying is I
wouldn't have chosen to do that. I agree that it would have been
better to do it that way originally, but I disagree with paying the
switching cost, especially in the back-branches.

--
Robert Haas
EDB: http://www.enterprisedb.com

#41Bertrand Drouvot
bertranddrouvot.pg@gmail.com
In reply to: Robert Haas (#40)
Re: Consistently use the XLogRecPtrIsInvalid() macro

Hi,

On Wed, Nov 19, 2025 at 12:27:30PM -0500, Robert Haas wrote:

On Wed, Nov 19, 2025 at 11:49 AM Álvaro Herrera <alvherre@kurilemu.de> wrote:

I'm rather late to the party here, but for what it's worth, I don't
really think this was a good idea. Anyone who wants to write
out-of-core code that works in the back-branches must still write it
the old way, or it will potentially fail on older minor releases.

No, they don't need to. Thus far, they can still keep their code the
way it is.

True, but if they write any new code, and care about it compiling with
older minor releases, this is a potential pitfall.

Why given that 06edbed4786 has been back patched through 13?

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

#42Andres Freund
andres@anarazel.de
In reply to: Robert Haas (#40)
Re: Consistently use the XLogRecPtrIsInvalid() macro

On 2025-11-19 12:27:30 -0500, Robert Haas wrote:

It's possible, but fundamentally I think it's about replacing
XLogRecPtrIsInvalid with XLogRecPtrIsValid, and what I'm saying is I
wouldn't have chosen to do that. I agree that it would have been
better to do it that way originally, but I disagree with paying the
switching cost, especially in the back-branches.

+1

This just seems like a lot of noise for something at most very mildly odd.

#43Robert Haas
robertmhaas@gmail.com
In reply to: Bertrand Drouvot (#41)
Re: Consistently use the XLogRecPtrIsInvalid() macro

On Wed, Nov 19, 2025 at 12:47 PM Bertrand Drouvot
<bertranddrouvot.pg@gmail.com> wrote:

True, but if they write any new code, and care about it compiling with
older minor releases, this is a potential pitfall.

Why given that 06edbed4786 has been back patched through 13?

I do not know how to make the phrase "older minor releases" any more
clear. You and Álvaro seem to be under the impression that nobody will
ever try to compile code written after this change from a point
release that we shipped before this change. While I don't think that
will be a common thing to do, I'm not sure where you get the idea that
older minor releases completely cease to be relevant when we release a
new one. That's just not how it works.

I bet if we look in a few years we'll find modules on PGXN that have
#ifdef logic in them to make sure they can work with both
XLogRecPtrIsInvalid and XLogRecPtrIsValid. Probably most won't; a lot
of extensions don't need either macro anyway. But what do you think
that an extension maintainer is going to do if their build breaks at
some point, on master or in the back-branches? Do you think they're
just going to do a hard switch to the new macro? Because that's not
what I will do if this breaks something I have to maintain. I'll
certainly make it work both ways, somehow or other. And I bet everyone
else will do the same.

And that would be totally fine and reasonable if this were fixing an
actual problem.

--
Robert Haas
EDB: http://www.enterprisedb.com

#44Álvaro Herrera
alvherre@kurilemu.de
In reply to: Robert Haas (#43)
Re: Consistently use the XLogRecPtrIsInvalid() macro

On 2025-Nov-19, Robert Haas wrote:

I do not know how to make the phrase "older minor releases" any more
clear.

It's perfectly clear. I just don't believe this claim.

You and Álvaro seem to be under the impression that nobody will
ever try to compile code written after this change from a point
release that we shipped before this change. While I don't think that
will be a common thing to do, I'm not sure where you get the idea that
older minor releases completely cease to be relevant when we release a
new one. That's just not how it works.

I'm sure compiled versions continue to be relevant, but I highly doubt
anybody compiles afresh with old minors.

I bet if we look in a few years we'll find modules on PGXN that have
#ifdef logic in them to make sure they can work with both
XLogRecPtrIsInvalid and XLogRecPtrIsValid.

Ok, let's wait a few years and see. My bet is you won't find any.

--
Álvaro Herrera Breisgau, Deutschland — https://www.EnterpriseDB.com/

#45Bertrand Drouvot
bertranddrouvot.pg@gmail.com
In reply to: Peter Eisentraut (#34)
1 attachment(s)
Re: Consistently use the XLogRecPtrIsInvalid() macro

Hi,

On Tue, Nov 18, 2025 at 04:54:32PM +0100, Peter Eisentraut wrote:

I mean, some people like writing if (!foo) and some like writing if
(foo == NULL), but we're not going to legislate one
over the other.

Agree. Out of curiosity, I searched for pointers and literal zero comparisons
or assignments (with [1]https://github.com/bdrouvot/coccinelle_on_pg/blob/main/misc/pointers_and_literal_zero.cocci) and found 6 of them.

While literal zero is technically correct, NULL is the semantically appropriate
choice for pointers.

PFA a patch to fix those 6.

[1]: https://github.com/bdrouvot/coccinelle_on_pg/blob/main/misc/pointers_and_literal_zero.cocci

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

Attachments:

v1-0001-Replace-pointer-comparisons-and-assignments-to-li.patchtext/x-diff; charset=us-asciiDownload
From d7c1055cf62bd6ce6ce6cf24e00407449ee91cc9 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Sat, 29 Nov 2025 05:19:02 +0000
Subject: [PATCH v1] Replace pointer comparisons and assignments to literal
 zero with NULL

While 0 is technically correct, NULL is the semantically appropriate choice for
pointers.
---
 src/backend/nodes/copyfuncs.c         | 2 +-
 src/backend/postmaster/postmaster.c   | 2 +-
 src/backend/utils/adt/pg_locale.c     | 4 ++--
 src/backend/utils/adt/timestamp.c     | 2 +-
 src/interfaces/ecpg/ecpglib/prepare.c | 2 +-
 5 files changed, 6 insertions(+), 6 deletions(-)
  24.3% src/backend/nodes/
  18.3% src/backend/postmaster/
  43.4% src/backend/utils/adt/
  13.9% src/interfaces/ecpg/ecpglib/

diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 475693b08bc..9b10cb096d1 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -204,7 +204,7 @@ copyObjectImpl(const void *from)
 
 		default:
 			elog(ERROR, "unrecognized node type: %d", (int) nodeTag(from));
-			retval = 0;			/* keep compiler quiet */
+			retval = NULL;			/* keep compiler quiet */
 			break;
 	}
 
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 7c064cf9fbb..a956db4ad27 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -3391,7 +3391,7 @@ LaunchMissingBackgroundProcesses(void)
 			Shutdown <= SmartShutdown)
 		{
 			WalReceiverPMChild = StartChildProcess(B_WAL_RECEIVER);
-			if (WalReceiverPMChild != 0)
+			if (WalReceiverPMChild != NULL)
 				WalReceiverRequested = false;
 			/* else leave the flag set, so we'll try again later */
 		}
diff --git a/src/backend/utils/adt/pg_locale.c b/src/backend/utils/adt/pg_locale.c
index b02e7fa4f18..b26257c0a8d 100644
--- a/src/backend/utils/adt/pg_locale.c
+++ b/src/backend/utils/adt/pg_locale.c
@@ -1222,10 +1222,10 @@ pg_newlocale_from_collation(Oid collid)
 		 * Make sure cache entry is marked invalid, in case we fail before
 		 * setting things.
 		 */
-		cache_entry->locale = 0;
+		cache_entry->locale = NULL;
 	}
 
-	if (cache_entry->locale == 0)
+	if (cache_entry->locale == NULL)
 	{
 		cache_entry->locale = create_pg_locale(collid, CollationCacheContext);
 	}
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 156a4830ffd..fda096f6c4e 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -5158,7 +5158,7 @@ interval_trunc(PG_FUNCTION_ARGS)
 							 errmsg("unit \"%s\" not supported for type %s",
 									lowunits, format_type_be(INTERVALOID)),
 							 (val == DTK_WEEK) ? errdetail("Months usually have fractional weeks.") : 0));
-					result = 0;
+					result = NULL;
 			}
 		}
 
diff --git a/src/interfaces/ecpg/ecpglib/prepare.c b/src/interfaces/ecpg/ecpglib/prepare.c
index 4b1ae839506..a3f51993d70 100644
--- a/src/interfaces/ecpg/ecpglib/prepare.c
+++ b/src/interfaces/ecpg/ecpglib/prepare.c
@@ -509,7 +509,7 @@ ecpg_freeStmtCacheEntry(int lineno, int compat,
 	if (entry->ecpgQuery)
 	{
 		ecpg_free(entry->ecpgQuery);
-		entry->ecpgQuery = 0;
+		entry->ecpgQuery = NULL;
 	}
 
 	return entNo;
-- 
2.34.1

#46Peter Eisentraut
peter@eisentraut.org
In reply to: Bertrand Drouvot (#45)
Re: Consistently use the XLogRecPtrIsInvalid() macro

On 01.12.25 08:14, Bertrand Drouvot wrote:

Hi,

On Tue, Nov 18, 2025 at 04:54:32PM +0100, Peter Eisentraut wrote:

I mean, some people like writing if (!foo) and some like writing if
(foo == NULL), but we're not going to legislate one
over the other.

Agree. Out of curiosity, I searched for pointers and literal zero comparisons
or assignments (with [1]) and found 6 of them.

While literal zero is technically correct, NULL is the semantically appropriate
choice for pointers.

PFA a patch to fix those 6.

committed (required pgindent)

#47Bertrand Drouvot
bertranddrouvot.pg@gmail.com
In reply to: Peter Eisentraut (#46)
Re: Consistently use the XLogRecPtrIsInvalid() macro

Hi,

On Tue, Dec 02, 2025 at 08:44:28AM +0100, Peter Eisentraut wrote:

On 01.12.25 08:14, Bertrand Drouvot wrote:

Hi,

On Tue, Nov 18, 2025 at 04:54:32PM +0100, Peter Eisentraut wrote:

I mean, some people like writing if (!foo) and some like writing if
(foo == NULL), but we're not going to legislate one
over the other.

Agree. Out of curiosity, I searched for pointers and literal zero comparisons
or assignments (with [1]) and found 6 of them.

While literal zero is technically correct, NULL is the semantically appropriate
choice for pointers.

PFA a patch to fix those 6.

committed (required pgindent)

Thanks!

Doh, I always run pgindent unless when I think the changes could not break the
indentation.

Note to self: always run pgindent, no thinking required ;-)

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com