From 50d97e0d84f41e98e0ec2846d1d43d6aa1bf1272 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Thu, 12 Feb 2026 09:16:48 +0000
Subject: [PATCH v1 3/5] Replace literal 0 with InvalidAttrNumber for
 AttrNumber assignments

Use the proper constant InvalidAttrNumber instead of literal 0 when
assigning AttrNumber variables and struct fields.

This improves code clarity by making it explicit that these are
invalid AttrNumber values rather than ambiguous zero literals.

Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Discussion:
---
 contrib/pg_visibility/pg_visibility.c    |  2 +-
 contrib/postgres_fdw/postgres_fdw.c      |  6 +++---
 src/backend/access/common/printtup.c     |  2 +-
 src/backend/access/common/tupdesc.c      |  2 +-
 src/backend/catalog/heap.c               |  2 +-
 src/backend/commands/copyfrom.c          |  2 +-
 src/backend/commands/indexcmds.c         |  2 +-
 src/backend/commands/sequence.c          |  2 +-
 src/backend/commands/tablecmds.c         |  9 +++++----
 src/backend/executor/execExpr.c          |  4 ++--
 src/backend/executor/execJunk.c          |  2 +-
 src/backend/executor/execMain.c          |  2 +-
 src/backend/executor/execTuples.c        | 22 +++++++++++-----------
 src/backend/executor/nodeFunctionscan.c  |  2 +-
 src/backend/executor/nodeIndexscan.c     |  2 +-
 src/backend/statistics/attribute_stats.c |  2 +-
 src/backend/statistics/dependencies.c    |  4 ++--
 src/backend/utils/adt/pg_dependencies.c  |  4 ++--
 src/backend/utils/adt/selfuncs.c         |  2 +-
 19 files changed, 38 insertions(+), 37 deletions(-)
   7.7% contrib/postgres_fdw/
   3.9% src/backend/access/common/
  23.1% src/backend/commands/
  45.2% src/backend/executor/
   7.0% src/backend/statistics/
   8.1% src/backend/utils/adt/

diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index 9bc3a784bf7..ae0ebc0d05a 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -454,7 +454,7 @@ pg_visibility_tupdesc(bool include_blkno, bool include_pd)
 {
 	TupleDesc	tupdesc;
 	AttrNumber	maxattr = 2;
-	AttrNumber	a = 0;
+	AttrNumber	a = InvalidAttrNumber;
 
 	if (include_blkno)
 		++maxattr;
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 3572689e33b..506836f3645 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -7536,7 +7536,7 @@ make_tuple_from_result_row(PGresult *res,
 	/*
 	 * Set up and install callback to report where conversion error occurs.
 	 */
-	errpos.cur_attno = 0;
+	errpos.cur_attno = InvalidAttrNumber;
 	errpos.rel = rel;
 	errpos.fsstate = fsstate;
 	errcallback.callback = conversion_error_callback;
@@ -7587,7 +7587,7 @@ make_tuple_from_result_row(PGresult *res,
 				ctid = (ItemPointer) DatumGetPointer(datum);
 			}
 		}
-		errpos.cur_attno = 0;
+		errpos.cur_attno = InvalidAttrNumber;
 
 		j++;
 	}
@@ -7664,7 +7664,7 @@ conversion_error_callback(void *arg)
 		/* ForeignScan case */
 		ForeignScan *fsplan = castNode(ForeignScan, fsstate->ss.ps.plan);
 		int			varno = 0;
-		AttrNumber	colno = 0;
+		AttrNumber	colno = InvalidAttrNumber;
 
 		if (fsplan->scan.scanrelid > 0)
 		{
diff --git a/src/backend/access/common/printtup.c b/src/backend/access/common/printtup.c
index 616bdafd395..f5672e74edd 100644
--- a/src/backend/access/common/printtup.c
+++ b/src/backend/access/common/printtup.c
@@ -224,7 +224,7 @@ SendRowDescriptionMessage(StringInfo buf, TupleDesc typeinfo,
 		{
 			/* No info available, so send zeroes */
 			resorigtbl = 0;
-			resorigcol = 0;
+			resorigcol = InvalidAttrNumber;
 		}
 
 		if (formats)
diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c
index b69d10f0a45..c318d91c0a3 100644
--- a/src/backend/access/common/tupdesc.c
+++ b/src/backend/access/common/tupdesc.c
@@ -1051,7 +1051,7 @@ BuildDescFromLists(const List *names, const List *types, const List *typmods, co
 	 */
 	desc = CreateTemplateTupleDesc(natts);
 
-	attnum = 0;
+	attnum = InvalidAttrNumber;
 	forfour(l1, names, l2, types, l3, typmods, l4, collations)
 	{
 		char	   *attname = strVal(lfirst(l1));
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index a6ed9849e77..9238043857d 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -2597,7 +2597,7 @@ AddRelationNewConstraints(Relation rel,
 			cooked->contype = CONSTR_CHECK;
 			cooked->conoid = constrOid;
 			cooked->name = ccname;
-			cooked->attnum = 0;
+			cooked->attnum = InvalidAttrNumber;
 			cooked->expr = expr;
 			cooked->is_enforced = cdef->is_enforced;
 			cooked->skip_validation = cdef->skip_validation;
diff --git a/src/backend/commands/copyfrom.c b/src/backend/commands/copyfrom.c
index 25ee20b23db..5a7005a921c 100644
--- a/src/backend/commands/copyfrom.c
+++ b/src/backend/commands/copyfrom.c
@@ -1740,7 +1740,7 @@ BeginCopyFrom(ParseState *pstate,
 		cstate->rteperminfos = pstate->p_rteperminfos;
 	}
 
-	num_defaults = 0;
+	num_defaults = InvalidAttrNumber;
 	volatile_defexprs = false;
 
 	/*
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 635679cc1f2..702a396b605 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -2009,7 +2009,7 @@ ComputeIndexAttrs(ParseState *pstate,
 			}
 			else
 			{
-				indexInfo->ii_IndexAttrNumbers[attn] = 0;	/* marks expression */
+				indexInfo->ii_IndexAttrNumbers[attn] = InvalidAttrNumber;	/* marks expression */
 				indexInfo->ii_Expressions = lappend(indexInfo->ii_Expressions,
 													expr);
 
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index e1b808bbb60..925213ee8c9 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1615,7 +1615,7 @@ process_owned_by(Relation seqrel, List *owned_by, bool for_identity)
 					 errmsg("invalid OWNED BY option"),
 					 errhint("Specify OWNED BY table.column or OWNED BY NONE.")));
 		tablerel = NULL;
-		attnum = 0;
+		attnum = InvalidAttrNumber;
 	}
 	else
 	{
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index f976c0e5c7e..4d035ae2558 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -991,7 +991,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
 	 */
 	rawDefaults = NIL;
 	cookedDefaults = NIL;
-	attnum = 0;
+	attnum = InvalidAttrNumber;
 
 	foreach(listptr, stmt->tableElts)
 	{
@@ -1391,7 +1391,7 @@ BuildDescForRelation(const List *columns)
 	natts = list_length(columns);
 	desc = CreateTemplateTupleDesc(natts);
 
-	attnum = 0;
+	attnum = InvalidAttrNumber;
 
 	foreach(l, columns)
 	{
@@ -9168,7 +9168,7 @@ SetIndexStorageProperties(Relation rel, Relation attrelation,
 	{
 		Oid			indexoid = lfirst_oid(lc);
 		Relation	indrel;
-		AttrNumber	indattnum = 0;
+		AttrNumber	indattnum = InvalidAttrNumber;
 		HeapTuple	tuple;
 
 		indrel = index_open(indexoid, lockmode);
@@ -19958,7 +19958,8 @@ ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNu
 			}
 			else
 			{
-				partattrs[attn] = 0;	/* marks the column as expression */
+				partattrs[attn] = InvalidAttrNumber;	/* marks the column as
+														 * expression */
 				*partexprs = lappend(*partexprs, expr);
 
 				/*
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index 088eca24021..01c09b8899f 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -396,7 +396,7 @@ ExecBuildProjectionInfo(List *targetList,
 	{
 		TargetEntry *tle = lfirst_node(TargetEntry, lc);
 		Var		   *variable = NULL;
-		AttrNumber	attnum = 0;
+		AttrNumber	attnum = InvalidAttrNumber;
 		bool		isSafeVar = false;
 
 		/*
@@ -4141,7 +4141,7 @@ ExecBuildHash32FromAttrs(TupleDesc desc, const TupleTableSlotOps *ops,
 	ExprEvalStep scratch = {0};
 	NullableDatum *iresult = NULL;
 	intptr_t	opcode;
-	AttrNumber	last_attnum = 0;
+	AttrNumber	last_attnum = InvalidAttrNumber;
 
 	Assert(numCols >= 0);
 
diff --git a/src/backend/executor/execJunk.c b/src/backend/executor/execJunk.c
index 3736bea3b3c..79a7e60c342 100644
--- a/src/backend/executor/execJunk.c
+++ b/src/backend/executor/execJunk.c
@@ -94,7 +94,7 @@ ExecInitJunkFilter(List *targetList, TupleTableSlot *slot)
 		ListCell   *t;
 
 		cleanMap = (AttrNumber *) palloc(cleanLength * sizeof(AttrNumber));
-		cleanResno = 0;
+		cleanResno = InvalidAttrNumber;
 		foreach(t, targetList)
 		{
 			TargetEntry *tle = lfirst(t);
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index bfd3ebc601e..4912989eac1 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -1284,7 +1284,7 @@ InitResultRelInfo(ResultRelInfo *resultRelInfo,
 		resultRelInfo->ri_FdwRoutine = NULL;
 
 	/* The following fields are set later if needed */
-	resultRelInfo->ri_RowIdAttNo = 0;
+	resultRelInfo->ri_RowIdAttNo = InvalidAttrNumber;
 	resultRelInfo->ri_extraUpdatedCols = NULL;
 	resultRelInfo->ri_projectNew = NULL;
 	resultRelInfo->ri_newTupleSlot = NULL;
diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c
index b768eae9e53..528ac05f7d9 100644
--- a/src/backend/executor/execTuples.c
+++ b/src/backend/executor/execTuples.c
@@ -117,7 +117,7 @@ tts_virtual_clear(TupleTableSlot *slot)
 		slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
 	}
 
-	slot->tts_nvalid = 0;
+	slot->tts_nvalid = InvalidAttrNumber;
 	slot->tts_flags |= TTS_FLAG_EMPTY;
 	ItemPointerSetInvalid(&slot->tts_tid);
 }
@@ -335,7 +335,7 @@ tts_heap_clear(TupleTableSlot *slot)
 		slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
 	}
 
-	slot->tts_nvalid = 0;
+	slot->tts_nvalid = InvalidAttrNumber;
 	slot->tts_flags |= TTS_FLAG_EMPTY;
 	ItemPointerSetInvalid(&slot->tts_tid);
 	hslot->off = 0;
@@ -413,7 +413,7 @@ tts_heap_materialize(TupleTableSlot *slot)
 	 * Have to deform from scratch, otherwise tts_values[] entries could point
 	 * into the non-materialized tuple (which might be gone when accessed).
 	 */
-	slot->tts_nvalid = 0;
+	slot->tts_nvalid = InvalidAttrNumber;
 	hslot->off = 0;
 
 	if (!hslot->tuple)
@@ -490,7 +490,7 @@ tts_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple, bool shouldFree)
 
 	tts_heap_clear(slot);
 
-	slot->tts_nvalid = 0;
+	slot->tts_nvalid = InvalidAttrNumber;
 	hslot->tuple = tuple;
 	hslot->off = 0;
 	slot->tts_flags &= ~(TTS_FLAG_EMPTY | TTS_FLAG_SHOULDFREE);
@@ -533,7 +533,7 @@ tts_minimal_clear(TupleTableSlot *slot)
 		slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
 	}
 
-	slot->tts_nvalid = 0;
+	slot->tts_nvalid = InvalidAttrNumber;
 	slot->tts_flags |= TTS_FLAG_EMPTY;
 	ItemPointerSetInvalid(&slot->tts_tid);
 	mslot->off = 0;
@@ -601,7 +601,7 @@ tts_minimal_materialize(TupleTableSlot *slot)
 	 * Have to deform from scratch, otherwise tts_values[] entries could point
 	 * into the non-materialized tuple (which might be gone when accessed).
 	 */
-	slot->tts_nvalid = 0;
+	slot->tts_nvalid = InvalidAttrNumber;
 	mslot->off = 0;
 
 	if (!mslot->mintuple)
@@ -689,7 +689,7 @@ tts_minimal_store_tuple(TupleTableSlot *slot, MinimalTuple mtup, bool shouldFree
 	Assert(TTS_EMPTY(slot));
 
 	slot->tts_flags &= ~TTS_FLAG_EMPTY;
-	slot->tts_nvalid = 0;
+	slot->tts_nvalid = InvalidAttrNumber;
 	mslot->off = 0;
 
 	mslot->mintuple = mtup;
@@ -739,7 +739,7 @@ tts_buffer_heap_clear(TupleTableSlot *slot)
 	if (BufferIsValid(bslot->buffer))
 		ReleaseBuffer(bslot->buffer);
 
-	slot->tts_nvalid = 0;
+	slot->tts_nvalid = InvalidAttrNumber;
 	slot->tts_flags |= TTS_FLAG_EMPTY;
 	ItemPointerSetInvalid(&slot->tts_tid);
 	bslot->base.tuple = NULL;
@@ -819,7 +819,7 @@ tts_buffer_heap_materialize(TupleTableSlot *slot)
 	 * into the non-materialized tuple (which might be gone when accessed).
 	 */
 	bslot->base.off = 0;
-	slot->tts_nvalid = 0;
+	slot->tts_nvalid = InvalidAttrNumber;
 
 	if (!bslot->base.tuple)
 	{
@@ -956,7 +956,7 @@ tts_buffer_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple,
 	}
 
 	slot->tts_flags &= ~TTS_FLAG_EMPTY;
-	slot->tts_nvalid = 0;
+	slot->tts_nvalid = InvalidAttrNumber;
 	bslot->base.tuple = tuple;
 	bslot->base.off = 0;
 	slot->tts_tid = tuple->t_self;
@@ -1327,7 +1327,7 @@ MakeTupleTableSlot(TupleDesc tupleDesc,
 		slot->tts_flags |= TTS_FLAG_FIXED;
 	slot->tts_tupleDescriptor = tupleDesc;
 	slot->tts_mcxt = CurrentMemoryContext;
-	slot->tts_nvalid = 0;
+	slot->tts_nvalid = InvalidAttrNumber;
 
 	if (tupleDesc != NULL)
 	{
diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c
index 63e605e1f81..1caa8046ac6 100644
--- a/src/backend/executor/nodeFunctionscan.c
+++ b/src/backend/executor/nodeFunctionscan.c
@@ -457,7 +457,7 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags)
 	}
 	else
 	{
-		AttrNumber	attno = 0;
+		AttrNumber	attno = InvalidAttrNumber;
 
 		if (node->funcordinality)
 			natts++;
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index a616abff04c..c38163b4519 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -1045,7 +1045,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
 			/* See cmp_orderbyvals() comments on NULLS LAST */
 			orderbysort->ssup_nulls_first = false;
 			/* ssup_attno is unused here and elsewhere */
-			orderbysort->ssup_attno = 0;
+			orderbysort->ssup_attno = InvalidAttrNumber;
 			/* No abbreviation */
 			orderbysort->abbreviate = false;
 			PrepareSortSupportFromOrderingOp(orderbyop, orderbysort);
diff --git a/src/backend/statistics/attribute_stats.c b/src/backend/statistics/attribute_stats.c
index a6b118a8d72..2aadf4fdfac 100644
--- a/src/backend/statistics/attribute_stats.c
+++ b/src/backend/statistics/attribute_stats.c
@@ -219,7 +219,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo)
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("must specify either \"%s\" or \"%s\"", "attname", "attnum")));
 		attname = NULL;			/* keep compiler quiet */
-		attnum = 0;
+		attnum = InvalidAttrNumber;
 	}
 
 	if (attnum < 0)
diff --git a/src/backend/statistics/dependencies.c b/src/backend/statistics/dependencies.c
index e3a2f5817e0..b2718f64604 100644
--- a/src/backend/statistics/dependencies.c
+++ b/src/backend/statistics/dependencies.c
@@ -174,7 +174,7 @@ DependencyGenerator_init(int n, int k)
 	state = palloc0_object(DependencyGeneratorData);
 	state->dependencies = palloc_array(AttrNumber, k);
 
-	state->ndependencies = 0;
+	state->ndependencies = InvalidAttrNumber;
 	state->current = 0;
 	state->k = k;
 	state->n = n;
@@ -1476,7 +1476,7 @@ dependencies_clauselist_selectivity(PlannerInfo *root,
 	if (unique_exprs_cnt > 0)
 		attnum_offset = (unique_exprs_cnt + 1);
 	else
-		attnum_offset = 0;
+		attnum_offset = InvalidAttrNumber;
 
 	/*
 	 * Now that we know how many expressions there are, we can offset the
diff --git a/src/backend/utils/adt/pg_dependencies.c b/src/backend/utils/adt/pg_dependencies.c
index d8bd1c4a168..1e7e1c2fd8d 100644
--- a/src/backend/utils/adt/pg_dependencies.c
+++ b/src/backend/utils/adt/pg_dependencies.c
@@ -236,7 +236,7 @@ dependencies_object_end(void *state)
 	 */
 	list_free(parse->attnum_list);
 	parse->attnum_list = NIL;
-	parse->dependency = 0;
+	parse->dependency = InvalidAttrNumber;
 	parse->degree = 0.0;
 	parse->found_attributes = false;
 	parse->found_dependency = false;
@@ -760,7 +760,7 @@ pg_dependencies_in(PG_FUNCTION_ARGS)
 	parse_state.state = DEPS_EXPECT_START;
 	parse_state.dependency_list = NIL;
 	parse_state.attnum_list = NIL;
-	parse_state.dependency = 0;
+	parse_state.dependency = InvalidAttrNumber;
 	parse_state.degree = 0.0;
 	parse_state.found_attributes = false;
 	parse_state.found_dependency = false;
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 29fec655593..bd9024cb99e 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -4693,7 +4693,7 @@ estimate_multivariate_ndistinct(PlannerInfo *root, RelOptInfo *rel,
 		if (matched_info->exprs)
 			attnum_offset = (list_length(matched_info->exprs) + 1);
 		else
-			attnum_offset = 0;
+			attnum_offset = InvalidAttrNumber;
 
 		/* see what actually matched */
 		foreach(lc2, *varinfos)
-- 
2.34.1

