Remove useless casting to the same type

Started by Bertrand Drouvotabout 2 months ago16 messages
#1Bertrand Drouvot
bertranddrouvot.pg@gmail.com
1 attachment(s)

Hi hackers,

Attached is a patch to $SUBJECT.

This is the same kind of idea as 7f798aca1d5 and ef8fe693606, as their presence
could cause risks of hiding actual type mismatches in the future or silently
discarding qualifiers. I think that it also improves readability.

Those have been found with a coccinelle script as:

"
@@
type T;
T E;
@@

- (T)
E
"

which removes casts when it's casting to the same type.

Note that it generated more that what is in the attached. I chose not to remove
some of them (mainly arithmetic ones) to keep the patch focused on what matters
here.

Thoughts?

Regards,

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

Attachments:

v1-0001-Remove-useless-casting-to-same-type.patchtext/x-diff; charset=us-asciiDownload
From 7b9e448e9028e4bf81bf0933c6c47a154f4098fa Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Wed, 19 Nov 2025 18:33:35 +0000
Subject: [PATCH v1] Remove useless casting to same type

Their presence could cause risks of hiding actual type mismatches in the future
or silently discarding qualifiers. It also improves readability.

Same kind of idea as 7f798aca1d5 and ef8fe693606.
---
 contrib/btree_gist/btree_utils_num.c          |  4 ++--
 contrib/cube/cube.c                           |  6 +++---
 contrib/fuzzystrmatch/dmetaphone.c            |  2 +-
 contrib/pgcrypto/mbuf.c                       |  2 +-
 src/backend/access/common/indextuple.c        |  2 +-
 src/backend/access/gin/gindatapage.c          |  8 ++++----
 src/backend/access/gin/gininsert.c            |  2 +-
 src/backend/access/hash/hash_xlog.c           |  8 ++++----
 src/backend/access/transam/twophase.c         |  2 +-
 src/backend/catalog/aclchk.c                  |  4 ++--
 src/backend/commands/tablecmds.c              |  2 +-
 src/backend/executor/execExpr.c               |  2 +-
 src/backend/executor/execExprInterp.c         |  2 +-
 src/backend/executor/execPartition.c          |  2 +-
 src/backend/executor/nodeTableFuncscan.c      |  2 +-
 src/backend/optimizer/geqo/geqo_pool.c        |  4 ++--
 src/backend/optimizer/plan/planner.c          |  4 ++--
 src/backend/optimizer/util/pathnode.c         |  2 +-
 src/backend/parser/analyze.c                  |  2 +-
 src/backend/parser/parse_expr.c               |  4 ++--
 src/backend/port/sysv_shmem.c                 |  2 +-
 src/backend/replication/walsender.c           |  2 +-
 src/backend/rewrite/rewriteHandler.c          |  2 +-
 src/backend/statistics/dependencies.c         |  4 ++--
 src/backend/statistics/extended_stats.c       |  4 ++--
 src/backend/statistics/mcv.c                  |  2 +-
 src/backend/storage/aio/aio.c                 |  6 +++---
 src/backend/storage/aio/method_io_uring.c     |  2 +-
 src/backend/storage/ipc/waiteventset.c        |  2 +-
 src/backend/storage/lmgr/predicate.c          |  2 +-
 src/backend/storage/lmgr/proc.c               |  8 ++++----
 src/backend/utils/adt/arrayfuncs.c            |  4 ++--
 src/backend/utils/adt/jsonfuncs.c             |  8 ++++----
 src/backend/utils/adt/ruleutils.c             |  2 +-
 src/bin/pg_dump/pg_dump.c                     |  8 ++++----
 src/common/sha1.c                             |  4 ++--
 src/interfaces/ecpg/ecpglib/descriptor.c      |  2 +-
 src/interfaces/ecpg/ecpglib/execute.c         | 20 +++++++++----------
 src/interfaces/ecpg/ecpglib/prepare.c         |  6 +++---
 src/port/win32ntdll.c                         |  2 +-
 .../modules/test_radixtree/test_radixtree.c   |  2 +-
 41 files changed, 80 insertions(+), 80 deletions(-)
   3.6% contrib/cube/
   3.2% contrib/
   7.7% src/backend/access/gin/
   5.4% src/backend/access/hash/
   5.7% src/backend/executor/
   6.0% src/backend/optimizer/
   3.3% src/backend/parser/
   3.7% src/backend/statistics/
   7.4% src/backend/storage/lmgr/
   4.2% src/backend/storage/
   8.0% src/backend/utils/adt/
   8.2% src/backend/
   5.7% src/bin/pg_dump/
  23.2% src/interfaces/ecpg/ecpglib/
   4.0% src/

diff --git a/contrib/btree_gist/btree_utils_num.c b/contrib/btree_gist/btree_utils_num.c
index 446fa930b92..1b9b70e9c33 100644
--- a/contrib/btree_gist/btree_utils_num.c
+++ b/contrib/btree_gist/btree_utils_num.c
@@ -181,8 +181,8 @@ gbt_num_union(GBT_NUMKEY *out, const GistEntryVector *entryvec, const gbtree_nin
 	cur = (GBT_NUMKEY *) DatumGetPointer((entryvec->vector[0].key));
 
 
-	o.lower = &((GBT_NUMKEY *) out)[0];
-	o.upper = &((GBT_NUMKEY *) out)[tinfo->size];
+	o.lower = out;
+	o.upper = &out[tinfo->size];
 
 	memcpy(out, cur, 2 * tinfo->size);
 
diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c
index 8d3654ab7aa..aa47e141f81 100644
--- a/contrib/cube/cube.c
+++ b/contrib/cube/cube.c
@@ -718,16 +718,16 @@ g_cube_internal_consistent(NDBOX *key,
 	switch (strategy)
 	{
 		case RTOverlapStrategyNumber:
-			retval = (bool) cube_overlap_v0(key, query);
+			retval = cube_overlap_v0(key, query);
 			break;
 		case RTSameStrategyNumber:
 		case RTContainsStrategyNumber:
 		case RTOldContainsStrategyNumber:
-			retval = (bool) cube_contains_v0(key, query);
+			retval = cube_contains_v0(key, query);
 			break;
 		case RTContainedByStrategyNumber:
 		case RTOldContainedByStrategyNumber:
-			retval = (bool) cube_overlap_v0(key, query);
+			retval = cube_overlap_v0(key, query);
 			break;
 		default:
 			retval = false;
diff --git a/contrib/fuzzystrmatch/dmetaphone.c b/contrib/fuzzystrmatch/dmetaphone.c
index 6627b2b8943..227d8b11ddc 100644
--- a/contrib/fuzzystrmatch/dmetaphone.c
+++ b/contrib/fuzzystrmatch/dmetaphone.c
@@ -327,7 +327,7 @@ GetAt(metastring *s, int pos)
 	if ((pos < 0) || (pos >= s->length))
 		return '\0';
 
-	return ((char) *(s->str + pos));
+	return *(s->str + pos);
 }
 
 
diff --git a/contrib/pgcrypto/mbuf.c b/contrib/pgcrypto/mbuf.c
index 99f8957b004..8dfc1b39d48 100644
--- a/contrib/pgcrypto/mbuf.c
+++ b/contrib/pgcrypto/mbuf.c
@@ -133,7 +133,7 @@ mbuf_create_from_data(uint8 *data, int len)
 	MBuf	   *mbuf;
 
 	mbuf = palloc(sizeof *mbuf);
-	mbuf->data = (uint8 *) data;
+	mbuf->data = data;
 	mbuf->buf_end = mbuf->data + len;
 	mbuf->data_end = mbuf->data + len;
 	mbuf->read_pos = mbuf->data;
diff --git a/src/backend/access/common/indextuple.c b/src/backend/access/common/indextuple.c
index 1986b943a28..3efa3889c6f 100644
--- a/src/backend/access/common/indextuple.c
+++ b/src/backend/access/common/indextuple.c
@@ -172,7 +172,7 @@ index_form_tuple_context(TupleDesc tupleDescriptor,
 					values,
 #endif
 					isnull,
-					(char *) tp + hoff,
+					tp + hoff,
 					data_size,
 					&tupmask,
 					(hasnull ? (bits8 *) tp + sizeof(IndexTupleData) : NULL));
diff --git a/src/backend/access/gin/gindatapage.c b/src/backend/access/gin/gindatapage.c
index 6c2c6194720..ab19a854cd7 100644
--- a/src/backend/access/gin/gindatapage.c
+++ b/src/backend/access/gin/gindatapage.c
@@ -607,11 +607,11 @@ dataBeginPlaceToPageLeaf(GinBtree btree, Buffer buf, GinBtreeStack *stack,
 
 		if (append)
 			elog(DEBUG2, "appended %d new items to block %u; %d bytes (%d to go)",
-				 maxitems, BufferGetBlockNumber(buf), (int) leaf->lsize,
+				 maxitems, BufferGetBlockNumber(buf), leaf->lsize,
 				 items->nitem - items->curitem - maxitems);
 		else
 			elog(DEBUG2, "inserted %d new items to block %u; %d bytes (%d to go)",
-				 maxitems, BufferGetBlockNumber(buf), (int) leaf->lsize,
+				 maxitems, BufferGetBlockNumber(buf), leaf->lsize,
 				 items->nitem - items->curitem - maxitems);
 	}
 	else
@@ -693,11 +693,11 @@ dataBeginPlaceToPageLeaf(GinBtree btree, Buffer buf, GinBtreeStack *stack,
 
 		if (append)
 			elog(DEBUG2, "appended %d items to block %u; split %d/%d (%d to go)",
-				 maxitems, BufferGetBlockNumber(buf), (int) leaf->lsize, (int) leaf->rsize,
+				 maxitems, BufferGetBlockNumber(buf), leaf->lsize, leaf->rsize,
 				 items->nitem - items->curitem - maxitems);
 		else
 			elog(DEBUG2, "inserted %d items to block %u; split %d/%d (%d to go)",
-				 maxitems, BufferGetBlockNumber(buf), (int) leaf->lsize, (int) leaf->rsize,
+				 maxitems, BufferGetBlockNumber(buf), leaf->lsize, leaf->rsize,
 				 items->nitem - items->curitem - maxitems);
 	}
 
diff --git a/src/backend/access/gin/gininsert.c b/src/backend/access/gin/gininsert.c
index c2b879b2bf6..f87c60a230c 100644
--- a/src/backend/access/gin/gininsert.c
+++ b/src/backend/access/gin/gininsert.c
@@ -2412,7 +2412,7 @@ _gin_parse_tuple_items(GinTuple *a)
 
 	Assert(ndecoded == a->nitems);
 
-	return (ItemPointer) items;
+	return items;
 }
 
 /*
diff --git a/src/backend/access/hash/hash_xlog.c b/src/backend/access/hash/hash_xlog.c
index 2a0145f3c9b..1a2626e443f 100644
--- a/src/backend/access/hash/hash_xlog.c
+++ b/src/backend/access/hash/hash_xlog.c
@@ -389,7 +389,7 @@ hash_xlog_split_allocate_page(XLogReaderState *record)
 
 			/* extract low and high masks. */
 			memcpy(&lowmask, data, sizeof(uint32));
-			highmask = (uint32 *) ((char *) data + sizeof(uint32));
+			highmask = (uint32 *) (data + sizeof(uint32));
 
 			/* update metapage */
 			metap->hashm_lowmask = lowmask;
@@ -405,7 +405,7 @@ hash_xlog_split_allocate_page(XLogReaderState *record)
 
 			/* extract information of overflow pages. */
 			memcpy(&ovflpoint, data, sizeof(uint32));
-			ovflpages = (uint32 *) ((char *) data + sizeof(uint32));
+			ovflpages = (uint32 *) (data + sizeof(uint32));
 
 			/* update metapage */
 			metap->hashm_spares[ovflpoint] = *ovflpages;
@@ -591,7 +591,7 @@ hash_xlog_move_page_contents(XLogReaderState *record)
 			OffsetNumber *unend;
 
 			unused = (OffsetNumber *) ptr;
-			unend = (OffsetNumber *) ((char *) ptr + len);
+			unend = (OffsetNumber *) (ptr + len);
 
 			if ((unend - unused) > 0)
 				PageIndexMultiDelete(page, unused, unend - unused);
@@ -902,7 +902,7 @@ hash_xlog_delete(XLogReaderState *record)
 			OffsetNumber *unend;
 
 			unused = (OffsetNumber *) ptr;
-			unend = (OffsetNumber *) ((char *) ptr + len);
+			unend = (OffsetNumber *) (ptr + len);
 
 			if ((unend - unused) > 0)
 				PageIndexMultiDelete(page, unused, unend - unused);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 89d0bfa7760..da282b71b41 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -1037,7 +1037,7 @@ save_state_data(const void *data, uint32 len)
 		records.tail->data = palloc(records.bytes_free);
 	}
 
-	memcpy(((char *) records.tail->data) + records.tail->len, data, len);
+	memcpy(records.tail->data + records.tail->len, data, len);
 	records.tail->len += padlen;
 	records.bytes_free -= padlen;
 	records.total_len += padlen;
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index cd139bd65a6..d183f2990ce 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -580,7 +580,7 @@ ExecuteGrantStmt(GrantStmt *stmt)
 				elog(ERROR, "AccessPriv node must specify privilege or columns");
 			priv = string_to_privilege(privnode->priv_name);
 
-			if (priv & ~((AclMode) all_privileges))
+			if (priv & ~all_privileges)
 				ereport(ERROR,
 						(errcode(ERRCODE_INVALID_GRANT_OPERATION),
 						 errmsg(errormsg, privilege_to_string(priv))));
@@ -1059,7 +1059,7 @@ ExecAlterDefaultPrivilegesStmt(ParseState *pstate, AlterDefaultPrivilegesStmt *s
 				elog(ERROR, "AccessPriv node must specify privilege");
 			priv = string_to_privilege(privnode->priv_name);
 
-			if (priv & ~((AclMode) all_privileges))
+			if (priv & ~all_privileges)
 				ereport(ERROR,
 						(errcode(ERRCODE_INVALID_GRANT_OPERATION),
 						 errmsg(errormsg, privilege_to_string(priv))));
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 23ebaa3f230..07e5b95782e 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -6205,7 +6205,7 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap)
 		NewColumnValue *ex = lfirst(l);
 
 		/* expr already planned */
-		ex->exprstate = ExecInitExpr((Expr *) ex->expr, NULL);
+		ex->exprstate = ExecInitExpr(ex->expr, NULL);
 	}
 
 	notnull_attrs = notnull_virtual_attrs = NIL;
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index f1569879b52..b05ff476a63 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -4807,7 +4807,7 @@ ExecInitJsonExpr(JsonExpr *jsexpr, ExprState *state,
 		var->typid = exprType((Node *) argexpr);
 		var->typmod = exprTypmod((Node *) argexpr);
 
-		ExecInitExprRec((Expr *) argexpr, state, &var->value, &var->isnull);
+		ExecInitExprRec(argexpr, state, &var->value, &var->isnull);
 
 		jsestate->args = lappend(jsestate->args, var);
 	}
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 0e1a74976f7..5e7bd933afc 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3283,7 +3283,7 @@ ExecEvalNextValueExpr(ExprState *state, ExprEvalStep *op)
 			*op->resvalue = Int32GetDatum((int32) newval);
 			break;
 		case INT8OID:
-			*op->resvalue = Int64GetDatum((int64) newval);
+			*op->resvalue = Int64GetDatum(newval);
 			break;
 		default:
 			elog(ERROR, "unsupported sequence type %u",
diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c
index aa12e9ad2ea..c123ff0d873 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -855,7 +855,7 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate,
 											&found_whole_row);
 					/* We ignore the value of found_whole_row. */
 					onconfl->oc_WhereClause =
-						ExecInitQual((List *) clause, &mtstate->ps);
+						ExecInitQual(clause, &mtstate->ps);
 				}
 			}
 		}
diff --git a/src/backend/executor/nodeTableFuncscan.c b/src/backend/executor/nodeTableFuncscan.c
index 83ade3f9437..4bae685d45a 100644
--- a/src/backend/executor/nodeTableFuncscan.c
+++ b/src/backend/executor/nodeTableFuncscan.c
@@ -363,7 +363,7 @@ tfuncInitialize(TableFuncScanState *tstate, ExprContext *econtext, Datum doc)
 		char	   *ns_uri;
 		char	   *ns_name;
 
-		value = ExecEvalExpr((ExprState *) expr, econtext, &isnull);
+		value = ExecEvalExpr(expr, econtext, &isnull);
 		if (isnull)
 			ereport(ERROR,
 					(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
diff --git a/src/backend/optimizer/geqo/geqo_pool.c b/src/backend/optimizer/geqo/geqo_pool.c
index b6de0d93f28..89e3d6a0277 100644
--- a/src/backend/optimizer/geqo/geqo_pool.c
+++ b/src/backend/optimizer/geqo/geqo_pool.c
@@ -47,8 +47,8 @@ alloc_pool(PlannerInfo *root, int pool_size, int string_length)
 
 	/* pool */
 	new_pool = (Pool *) palloc(sizeof(Pool));
-	new_pool->size = (int) pool_size;
-	new_pool->string_length = (int) string_length;
+	new_pool->size = pool_size;
+	new_pool->string_length = string_length;
 
 	/* all chromosome */
 	new_pool->data = (Chromosome *) palloc(pool_size * sizeof(Chromosome));
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index c4fd646b999..0e78628bf01 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -3949,7 +3949,7 @@ make_grouping_rel(PlannerInfo *root, RelOptInfo *input_rel,
 	 * target list and HAVING quals are parallel-safe.
 	 */
 	if (input_rel->consider_parallel && target_parallel_safe &&
-		is_parallel_safe(root, (Node *) havingQual))
+		is_parallel_safe(root, havingQual))
 		grouped_rel->consider_parallel = true;
 
 	/*
@@ -8525,7 +8525,7 @@ create_unique_paths(PlannerInfo *root, RelOptInfo *rel, SpecialJoinInfo *sjinfo)
 			tle = tlist_member(uniqexpr, newtlist);
 			if (!tle)
 			{
-				tle = makeTargetEntry((Expr *) uniqexpr,
+				tle = makeTargetEntry(uniqexpr,
 									  nextresno,
 									  NULL,
 									  false);
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index e4fd6950fad..5693bd943f5 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -3864,7 +3864,7 @@ reparameterize_path(PlannerInfo *root, Path *path,
 		case T_SeqScan:
 			return create_seqscan_path(root, rel, required_outer, 0);
 		case T_SampleScan:
-			return (Path *) create_samplescan_path(root, rel, required_outer);
+			return create_samplescan_path(root, rel, required_outer);
 		case T_IndexScan:
 		case T_IndexOnlyScan:
 			{
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 3b392b084ad..e2d47aff107 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -428,7 +428,7 @@ transformStmt(ParseState *pstate, Node *parseTree)
 			 */
 			result = makeNode(Query);
 			result->commandType = CMD_UTILITY;
-			result->utilityStmt = (Node *) parseTree;
+			result->utilityStmt = parseTree;
 			break;
 	}
 
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 32d6ae918ca..75e505492ce 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -327,7 +327,7 @@ transformExprRecurse(ParseState *pstate, Node *expr)
 		case T_CaseTestExpr:
 		case T_Var:
 			{
-				result = (Node *) expr;
+				result = expr;
 				break;
 			}
 
@@ -4079,7 +4079,7 @@ transformJsonParseArg(ParseState *pstate, Node *jsexpr, JsonFormat *format,
 
 		if (*exprtype == UNKNOWNOID || typcategory == TYPCATEGORY_STRING)
 		{
-			expr = coerce_to_target_type(pstate, (Node *) expr, *exprtype,
+			expr = coerce_to_target_type(pstate, expr, *exprtype,
 										 TEXTOID, -1,
 										 COERCION_IMPLICIT,
 										 COERCE_IMPLICIT_CAST, -1);
diff --git a/src/backend/port/sysv_shmem.c b/src/backend/port/sysv_shmem.c
index 197926d44f6..298ceb3e218 100644
--- a/src/backend/port/sysv_shmem.c
+++ b/src/backend/port/sysv_shmem.c
@@ -206,7 +206,7 @@ InternalIpcMemoryCreate(IpcMemoryKey memKey, Size size)
 				 */
 				if (shmctl(shmid, IPC_RMID, NULL) < 0)
 					elog(LOG, "shmctl(%d, %d, 0) failed: %m",
-						 (int) shmid, IPC_RMID);
+						 shmid, IPC_RMID);
 			}
 		}
 
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index fc8f8559073..a1b4301a4ee 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -3074,7 +3074,7 @@ InitWalSenderSlot(void)
 
 			SpinLockRelease(&walsnd->mutex);
 			/* don't need the lock anymore */
-			MyWalSnd = (WalSnd *) walsnd;
+			MyWalSnd = walsnd;
 
 			break;
 		}
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index adc9e7600e1..c0d6d0b10a5 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -3781,7 +3781,7 @@ rewriteTargetView(Query *parsetree, Relation view)
 				parsetree->hasSubLinks = checkExprHasSubLink(viewqual);
 		}
 		else
-			AddQual(parsetree, (Node *) viewqual);
+			AddQual(parsetree, viewqual);
 	}
 
 	/*
diff --git a/src/backend/statistics/dependencies.c b/src/backend/statistics/dependencies.c
index 6f63b4f3ffb..d7bf6b7e846 100644
--- a/src/backend/statistics/dependencies.c
+++ b/src/backend/statistics/dependencies.c
@@ -785,7 +785,7 @@ dependency_is_compatible_clause(Node *clause, Index relid, AttrNumber *attnum)
 		 * A boolean expression "x" can be interpreted as "x = true", so
 		 * proceed with seeing if it's a suitable Var.
 		 */
-		clause_expr = (Node *) clause;
+		clause_expr = clause;
 	}
 
 	/*
@@ -1212,7 +1212,7 @@ dependency_is_compatible_expression(Node *clause, Index relid, List *statlist, N
 		 * A boolean expression "x" can be interpreted as "x = true", so
 		 * proceed with seeing if it's a suitable Var.
 		 */
-		clause_expr = (Node *) clause;
+		clause_expr = clause;
 	}
 
 	/*
diff --git a/src/backend/statistics/extended_stats.c b/src/backend/statistics/extended_stats.c
index 3c3d2d315c6..f003d7b4a73 100644
--- a/src/backend/statistics/extended_stats.c
+++ b/src/backend/statistics/extended_stats.c
@@ -2054,13 +2054,13 @@ examine_opclause_args(List *args, Node **exprp, Const **cstp,
 
 	if (IsA(rightop, Const))
 	{
-		expr = (Node *) leftop;
+		expr = leftop;
 		cst = (Const *) rightop;
 		expronleft = true;
 	}
 	else if (IsA(leftop, Const))
 	{
-		expr = (Node *) rightop;
+		expr = rightop;
 		cst = (Const *) leftop;
 		expronleft = false;
 	}
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index f59fb821543..28f925f397e 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1037,7 +1037,7 @@ statext_mcv_deserialize(bytea *data)
 	/* pointer to the data part (skip the varlena header) */
 	raw = (char *) data;
 	ptr = VARDATA_ANY(raw);
-	endptr = (char *) raw + VARSIZE_ANY(data);
+	endptr = raw + VARSIZE_ANY(data);
 
 	/* get the header and perform further sanity checks */
 	memcpy(&mcvlist->magic, ptr, sizeof(uint32));
diff --git a/src/backend/storage/aio/aio.c b/src/backend/storage/aio/aio.c
index dcc47069757..a12b785ade6 100644
--- a/src/backend/storage/aio/aio.c
+++ b/src/backend/storage/aio/aio.c
@@ -603,7 +603,7 @@ pgaio_io_wait(PgAioHandle *ioh, uint64 ref_generation)
 		if (pgaio_io_was_recycled(ioh, ref_generation, &state))
 			return;
 
-		switch ((PgAioHandleState) state)
+		switch (state)
 		{
 			case PGAIO_HS_IDLE:
 			case PGAIO_HS_HANDED_OUT:
@@ -908,7 +908,7 @@ static const char *
 pgaio_io_state_get_name(PgAioHandleState s)
 {
 #define PGAIO_HS_TOSTR_CASE(sym) case PGAIO_HS_##sym: return #sym
-	switch ((PgAioHandleState) s)
+	switch (s)
 	{
 			PGAIO_HS_TOSTR_CASE(IDLE);
 			PGAIO_HS_TOSTR_CASE(HANDED_OUT);
@@ -933,7 +933,7 @@ pgaio_io_get_state_name(PgAioHandle *ioh)
 const char *
 pgaio_result_status_string(PgAioResultStatus rs)
 {
-	switch ((PgAioResultStatus) rs)
+	switch (rs)
 	{
 		case PGAIO_RS_UNKNOWN:
 			return "UNKNOWN";
diff --git a/src/backend/storage/aio/method_io_uring.c b/src/backend/storage/aio/method_io_uring.c
index bb06da63a8e..00cb017ca3c 100644
--- a/src/backend/storage/aio/method_io_uring.c
+++ b/src/backend/storage/aio/method_io_uring.c
@@ -300,7 +300,7 @@ pgaio_uring_shmem_init(bool first_time)
 	if (pgaio_uring_caps.mem_init_size > 0)
 	{
 		ring_mem_remain = pgaio_uring_ring_shmem_size();
-		ring_mem_next = (char *) shmem;
+		ring_mem_next = shmem;
 
 		/* align to page boundary, see also pgaio_uring_ring_shmem_size() */
 		ring_mem_next = (char *) TYPEALIGN(sysconf(_SC_PAGESIZE), ring_mem_next);
diff --git a/src/backend/storage/ipc/waiteventset.c b/src/backend/storage/ipc/waiteventset.c
index 465cee40ccc..b5431ad3c5c 100644
--- a/src/backend/storage/ipc/waiteventset.c
+++ b/src/backend/storage/ipc/waiteventset.c
@@ -1477,7 +1477,7 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,
 	struct pollfd *cur_pollfd;
 
 	/* Sleep */
-	rc = poll(set->pollfds, set->nevents, (int) cur_timeout);
+	rc = poll(set->pollfds, set->nevents, cur_timeout);
 
 	/* Check return code */
 	if (rc < 0)
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index bb807d8c9cd..f12f8f77aad 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -4988,7 +4988,7 @@ predicatelock_twophase_recover(FullTransactionId fxid, uint16 info,
 											   HASH_ENTER, &found);
 		Assert(sxid != NULL);
 		Assert(!found);
-		sxid->myXact = (SERIALIZABLEXACT *) sxact;
+		sxid->myXact = sxact;
 
 		/*
 		 * Update global xmin. Note that this is a special case compared to
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 1504fafe6d8..ebc3f4ca457 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -244,7 +244,7 @@ InitProcGlobal(void)
 	MemSet(ptr, 0, requestSize);
 
 	procs = (PGPROC *) ptr;
-	ptr = (char *) ptr + TotalProcs * sizeof(PGPROC);
+	ptr = ptr + TotalProcs * sizeof(PGPROC);
 
 	ProcGlobal->allProcs = procs;
 	/* XXX allProcCount isn't really all of them; it excludes prepared xacts */
@@ -258,13 +258,13 @@ InitProcGlobal(void)
 	 * how hotly they are accessed.
 	 */
 	ProcGlobal->xids = (TransactionId *) ptr;
-	ptr = (char *) ptr + (TotalProcs * sizeof(*ProcGlobal->xids));
+	ptr = ptr + (TotalProcs * sizeof(*ProcGlobal->xids));
 
 	ProcGlobal->subxidStates = (XidCacheStatus *) ptr;
-	ptr = (char *) ptr + (TotalProcs * sizeof(*ProcGlobal->subxidStates));
+	ptr = ptr + (TotalProcs * sizeof(*ProcGlobal->subxidStates));
 
 	ProcGlobal->statusFlags = (uint8 *) ptr;
-	ptr = (char *) ptr + (TotalProcs * sizeof(*ProcGlobal->statusFlags));
+	ptr = ptr + (TotalProcs * sizeof(*ProcGlobal->statusFlags));
 
 	/* make sure wer didn't overflow */
 	Assert((ptr > (char *) procs) && (ptr <= (char *) procs + requestSize));
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c
index a464349ee33..5a1b8483bea 100644
--- a/src/backend/utils/adt/arrayfuncs.c
+++ b/src/backend/utils/adt/arrayfuncs.c
@@ -2257,7 +2257,7 @@ array_set_element(Datum arraydatum,
 
 		resultarray = (char *) palloc(arraytyplen);
 		memcpy(resultarray, DatumGetPointer(arraydatum), arraytyplen);
-		elt_ptr = (char *) resultarray + indx[0] * elmlen;
+		elt_ptr = resultarray + indx[0] * elmlen;
 		ArrayCastAndSet(dataValue, elmlen, elmbyval, elmalign, elt_ptr);
 		return PointerGetDatum(resultarray);
 	}
@@ -2418,7 +2418,7 @@ array_set_element(Datum arraydatum,
 			olditemlen = att_addlength_pointer(0, elmlen, elt_ptr);
 			olditemlen = att_align_nominal(olditemlen, elmalign);
 		}
-		lenafter = (int) (olddatasize - lenbefore - olditemlen);
+		lenafter = olddatasize - lenbefore - olditemlen;
 	}
 
 	if (isNull)
diff --git a/src/backend/utils/adt/jsonfuncs.c b/src/backend/utils/adt/jsonfuncs.c
index 8898f0f90a1..eaae8cf4665 100644
--- a/src/backend/utils/adt/jsonfuncs.c
+++ b/src/backend/utils/adt/jsonfuncs.c
@@ -5414,8 +5414,8 @@ setPathObject(JsonbIterator **it, const Datum *path_elems, const bool *path_null
 		newkey.val.string.len = VARSIZE_ANY_EXHDR(pathelem);
 
 		(void) pushJsonbValue(st, WJB_KEY, &newkey);
-		(void) push_path(st, level, path_elems, path_nulls,
-						 path_len, newval);
+		push_path(st, level, path_elems, path_nulls,
+				  path_len, newval);
 
 		/* Result is closed with WJB_END_OBJECT outside of this function */
 	}
@@ -5583,8 +5583,8 @@ setPathArray(JsonbIterator **it, const Datum *path_elems, const bool *path_nulls
 		if (idx > 0)
 			push_null_elements(st, idx - nelems);
 
-		(void) push_path(st, level, path_elems, path_nulls,
-						 path_len, newval);
+		push_path(st, level, path_elems, path_nulls,
+				  path_len, newval);
 
 		/* Result is closed with WJB_END_OBJECT outside of this function */
 	}
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 556ab057e5a..6cf90be40bb 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -10151,7 +10151,7 @@ get_rule_expr(Node *node, deparse_context *context,
 
 						if (needcomma)
 							appendStringInfoString(buf, ", ");
-						get_rule_expr((Node *) e, context, true);
+						get_rule_expr(e, context, true);
 						appendStringInfo(buf, " AS %s",
 										 quote_identifier(map_xml_name_to_sql_identifier(argname)));
 						needcomma = true;
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index a00918bacb4..2445085dbbd 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -2182,7 +2182,7 @@ selectDumpableCast(CastInfo *cast, Archive *fout)
 	 * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
 	 * support ACLs currently.
 	 */
-	if (cast->dobj.catId.oid <= (Oid) g_last_builtin_oid)
+	if (cast->dobj.catId.oid <= g_last_builtin_oid)
 		cast->dobj.dump = DUMP_COMPONENT_NONE;
 	else
 		cast->dobj.dump = fout->dopt->include_everything ?
@@ -2214,7 +2214,7 @@ selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
 		plang->dobj.dump = DUMP_COMPONENT_NONE;
 	else
 	{
-		if (plang->dobj.catId.oid <= (Oid) g_last_builtin_oid)
+		if (plang->dobj.catId.oid <= g_last_builtin_oid)
 			plang->dobj.dump = fout->remoteVersion < 90600 ?
 				DUMP_COMPONENT_NONE : DUMP_COMPONENT_ACL;
 		else
@@ -2247,7 +2247,7 @@ selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
 	 * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
 	 * they do not support ACLs currently.
 	 */
-	if (method->dobj.catId.oid <= (Oid) g_last_builtin_oid)
+	if (method->dobj.catId.oid <= g_last_builtin_oid)
 		method->dobj.dump = DUMP_COMPONENT_NONE;
 	else
 		method->dobj.dump = fout->dopt->include_everything ?
@@ -2273,7 +2273,7 @@ selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
 	 * change permissions on their member objects, if they wish to, and have
 	 * those changes preserved.
 	 */
-	if (extinfo->dobj.catId.oid <= (Oid) g_last_builtin_oid)
+	if (extinfo->dobj.catId.oid <= g_last_builtin_oid)
 		extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
 	else
 	{
diff --git a/src/common/sha1.c b/src/common/sha1.c
index f29866f8359..027574621b5 100644
--- a/src/common/sha1.c
+++ b/src/common/sha1.c
@@ -277,7 +277,7 @@ sha1_result(uint8 *digest0, pg_sha1_ctx *ctx)
 {
 	uint8	   *digest;
 
-	digest = (uint8 *) digest0;
+	digest = digest0;
 
 #ifdef WORDS_BIGENDIAN
 	memmove(digest, &ctx->h.b8[0], 20);
@@ -337,7 +337,7 @@ pg_sha1_update(pg_sha1_ctx *ctx, const uint8 *data, size_t len)
 	size_t		off;
 	size_t		copysiz;
 
-	input = (const uint8 *) data;
+	input = data;
 	off = 0;
 
 	while (off < len)
diff --git a/src/interfaces/ecpg/ecpglib/descriptor.c b/src/interfaces/ecpg/ecpglib/descriptor.c
index 466428edfeb..39cd5130ec9 100644
--- a/src/interfaces/ecpg/ecpglib/descriptor.c
+++ b/src/interfaces/ecpg/ecpglib/descriptor.c
@@ -113,7 +113,7 @@ get_int_item(int lineno, void *var, enum ECPGttype vartype, int value)
 			*(short *) var = (short) value;
 			break;
 		case ECPGt_int:
-			*(int *) var = (int) value;
+			*(int *) var = value;
 			break;
 		case ECPGt_long:
 			*(long *) var = (long) value;
diff --git a/src/interfaces/ecpg/ecpglib/execute.c b/src/interfaces/ecpg/ecpglib/execute.c
index 84a4a9fc578..a89d6c510c4 100644
--- a/src/interfaces/ecpg/ecpglib/execute.c
+++ b/src/interfaces/ecpg/ecpglib/execute.c
@@ -54,7 +54,7 @@ quote_postgres(char *arg, bool quote, int lineno)
 	{
 		length = strlen(arg);
 		buffer_len = 2 * length + 1;
-		res = (char *) ecpg_alloc(buffer_len + 3, lineno);
+		res = ecpg_alloc(buffer_len + 3, lineno);
 		if (!res)
 			return res;
 		escaped_len = PQescapeString(res + 1, arg, buffer_len);
@@ -263,7 +263,7 @@ ecpg_is_type_an_array(int type, const struct statement *stmt, const struct varia
 			return cache_entry->isarray;
 	}
 
-	array_query = (char *) ecpg_alloc(strlen("select typlen from pg_type where oid= and typelem<>0") + 11, stmt->lineno);
+	array_query = ecpg_alloc(strlen("select typlen from pg_type where oid= and typelem<>0") + 11, stmt->lineno);
 	if (array_query == NULL)
 		return ECPG_ARRAY_ERROR;
 
@@ -391,7 +391,7 @@ ecpg_store_result(const PGresult *results, int act_field,
 		}
 
 		ecpg_log("ecpg_store_result on line %d: allocating memory for %d tuples\n", stmt->lineno, ntuples);
-		var->value = (char *) ecpg_auto_alloc(len, stmt->lineno);
+		var->value = ecpg_auto_alloc(len, stmt->lineno);
 		if (!var->value)
 			return false;
 		*((char **) var->pointer) = var->value;
@@ -402,7 +402,7 @@ ecpg_store_result(const PGresult *results, int act_field,
 	{
 		int			len = var->ind_offset * ntuples;
 
-		var->ind_value = (char *) ecpg_auto_alloc(len, stmt->lineno);
+		var->ind_value = ecpg_auto_alloc(len, stmt->lineno);
 		if (!var->ind_value)
 			return false;
 		*((char **) var->ind_pointer) = var->ind_value;
@@ -822,7 +822,7 @@ ecpg_store_input(const int lineno, const bool force_indicator, const struct vari
 					struct ECPGgeneric_bytea *variable =
 						(struct ECPGgeneric_bytea *) (var->value);
 
-					if (!(mallocedval = (char *) ecpg_alloc(variable->len, lineno)))
+					if (!(mallocedval = ecpg_alloc(variable->len, lineno)))
 						return false;
 
 					memcpy(mallocedval, variable->arr, variable->len);
@@ -835,7 +835,7 @@ ecpg_store_input(const int lineno, const bool force_indicator, const struct vari
 					struct ECPGgeneric_varchar *variable =
 						(struct ECPGgeneric_varchar *) (var->value);
 
-					if (!(newcopy = (char *) ecpg_alloc(variable->len + 1, lineno)))
+					if (!(newcopy = ecpg_alloc(variable->len + 1, lineno)))
 						return false;
 
 					strncpy(newcopy, variable->arr, variable->len);
@@ -1128,9 +1128,9 @@ insert_tobeinserted(int position, int ph_len, struct statement *stmt, char *tobe
 {
 	char	   *newcopy;
 
-	if (!(newcopy = (char *) ecpg_alloc(strlen(stmt->command)
-										+ strlen(tobeinserted)
-										+ 1, stmt->lineno)))
+	if (!(newcopy = ecpg_alloc(strlen(stmt->command)
+							   + strlen(tobeinserted)
+							   + 1, stmt->lineno)))
 	{
 		ecpg_free(tobeinserted);
 		return false;
@@ -1536,7 +1536,7 @@ ecpg_build_params(struct statement *stmt)
 				int			buffersize = sizeof(int) * CHAR_BIT * 10 / 3;	/* a rough guess of the
 																			 * size we need */
 
-				if (!(tobeinserted = (char *) ecpg_alloc(buffersize, stmt->lineno)))
+				if (!(tobeinserted = ecpg_alloc(buffersize, stmt->lineno)))
 				{
 					ecpg_free_params(stmt, false);
 					return false;
diff --git a/src/interfaces/ecpg/ecpglib/prepare.c b/src/interfaces/ecpg/ecpglib/prepare.c
index 4b1ae839506..357d3956b8c 100644
--- a/src/interfaces/ecpg/ecpglib/prepare.c
+++ b/src/interfaces/ecpg/ecpglib/prepare.c
@@ -138,14 +138,14 @@ replace_variables(char **text, int lineno)
 			char	   *buffer,
 					   *newcopy;
 
-			if (!(buffer = (char *) ecpg_alloc(buffersize, lineno)))
+			if (!(buffer = ecpg_alloc(buffersize, lineno)))
 				return false;
 
 			snprintf(buffer, buffersize, "$%d", counter++);
 
 			for (len = 1; (*text)[ptr + len] && isvarchar((*text)[ptr + len]); len++)
 				 /* skip */ ;
-			if (!(newcopy = (char *) ecpg_alloc(strlen(*text) - len + strlen(buffer) + 1, lineno)))
+			if (!(newcopy = ecpg_alloc(strlen(*text) - len + strlen(buffer) + 1, lineno)))
 			{
 				ecpg_free(buffer);
 				return false;
@@ -302,7 +302,7 @@ deallocate_one(int lineno, enum COMPAT_MODE c, struct connection *con,
 		char	   *text;
 		PGresult   *query;
 
-		text = (char *) ecpg_alloc(strlen("deallocate \"\" ") + strlen(this->name), this->stmt->lineno);
+		text = ecpg_alloc(strlen("deallocate \"\" ") + strlen(this->name), this->stmt->lineno);
 
 		if (text)
 		{
diff --git a/src/port/win32ntdll.c b/src/port/win32ntdll.c
index ab6820fb8e5..1d3407f5a44 100644
--- a/src/port/win32ntdll.c
+++ b/src/port/win32ntdll.c
@@ -62,7 +62,7 @@ initialize_ntdll(void)
 			return -1;
 		}
 
-		*(pg_funcptr_t *) routines[i].address = address;
+		*routines[i].address = address;
 	}
 
 	initialized = true;
diff --git a/src/test/modules/test_radixtree/test_radixtree.c b/src/test/modules/test_radixtree/test_radixtree.c
index 787162c8793..606d8d3cd2d 100644
--- a/src/test/modules/test_radixtree/test_radixtree.c
+++ b/src/test/modules/test_radixtree/test_radixtree.c
@@ -219,7 +219,7 @@ test_basic(rt_node_class_test_elem *test_info, int shift, bool asc)
 		TestValueType update = keys[i] + 1;
 
 		/* rt_set should report the key found */
-		EXPECT_TRUE(rt_set(radixtree, keys[i], (TestValueType *) &update));
+		EXPECT_TRUE(rt_set(radixtree, keys[i], &update));
 	}
 
 	/* delete and re-insert keys */
-- 
2.34.1

#2Nathan Bossart
nathandbossart@gmail.com
In reply to: Bertrand Drouvot (#1)
Re: Remove useless casting to the same type

On Mon, Nov 24, 2025 at 10:26:32AM +0000, Bertrand Drouvot wrote:

This is the same kind of idea as 7f798aca1d5 and ef8fe693606, as their presence
could cause risks of hiding actual type mismatches in the future or silently
discarding qualifiers. I think that it also improves readability.

Seems reasonable to me.

Note that it generated more that what is in the attached. I chose not to remove
some of them (mainly arithmetic ones) to keep the patch focused on what matters
here.

Can you give an example of what you are talking about here?

--
nathan

#3Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Bertrand Drouvot (#1)
Re: Remove useless casting to the same type

On Mon, Nov 24, 2025 at 2:26 AM Bertrand Drouvot
<bertranddrouvot.pg@gmail.com> wrote:

Attached is a patch to $SUBJECT.

--- a/src/backend/access/gin/gindatapage.c
+++ b/src/backend/access/gin/gindatapage.c
@@ -607,11 +607,11 @@ dataBeginPlaceToPageLeaf(GinBtree btree, Buffer buf, GinBtreeStack *stack,
if (append)
elog(DEBUG2, "appended %d new items to block %u; %d bytes (%d to go)",
- maxitems, BufferGetBlockNumber(buf), (int) leaf->lsize,
+ maxitems, BufferGetBlockNumber(buf), leaf->lsize,
items->nitem - items->curitem - maxitems);

Hm. How do we feel, as a group, about superstitious casts in variadic
calls? I don't feel like they're in the same class as the other fixes.

Argument for: it's nice to know at a glance that a printf() invocation
won't corrupt something horribly, especially if I'm quickly scanning
code during a CVE analysis, and especially if the variable is named as
if it could maybe be a size_t. Do our compilers warn us well enough
now, in practice?

Argument against: it takes up precious columns and focuses attention
away from other things. Like the fact that (items->nitem -
items->curitem - maxitems) is unsigned and printed as signed here. :D
Maybe we should make the code compile cleanly under
-Wformat-signedness at some point... (not in this patch, not signing
you up for that)

@@ -389,7 +389,7 @@ hash_xlog_split_allocate_page(XLogReaderState *record)

/* extract low and high masks. */
memcpy(&lowmask, data, sizeof(uint32));
- highmask = (uint32 *) ((char *) data + sizeof(uint32));
+ highmask = (uint32 *) (data + sizeof(uint32));

I wonder about these, too. I like knowing what the code does without
having to check the type of `data`. But then later on we do a `data +=
sizeof(uint32) * 2`, so you have to check the type anyway, so... I
don't know.

+++ b/contrib/fuzzystrmatch/dmetaphone.c
@@ -327,7 +327,7 @@ GetAt(metastring *s, int pos)
if ((pos < 0) || (pos >= s->length))
return '\0';
- return ((char) *(s->str + pos));
+ return *(s->str + pos);

Isn't this just s->str[pos]? Ditto for SetAt(), right afterwards.

--Jacob

#4Bertrand Drouvot
bertranddrouvot.pg@gmail.com
In reply to: Nathan Bossart (#2)
1 attachment(s)
Re: Remove useless casting to the same type

Hi,

On Mon, Nov 24, 2025 at 12:43:28PM -0600, Nathan Bossart wrote:

On Mon, Nov 24, 2025 at 10:26:32AM +0000, Bertrand Drouvot wrote:

This is the same kind of idea as 7f798aca1d5 and ef8fe693606, as their presence
could cause risks of hiding actual type mismatches in the future or silently
discarding qualifiers. I think that it also improves readability.

Seems reasonable to me.

Thanks for looking at it!

Note that it generated more that what is in the attached. I chose not to remove
some of them (mainly arithmetic ones) to keep the patch focused on what matters
here.

Can you give an example of what you are talking about here?

Things like:

A)

- int   k = (int) (targrows * sampler_random_fract(&rstate.randstate));
+ int   k = (targrows * sampler_random_fract(&rstate.randstate));

That's a valid cast removal but I'm not sure about the removal added value here.

B)
- sign = (BITVECP) (((char *) sign) + 1);
+ sign = ((sign) + 1);

BITVECP is "typedef char *BITVECP; So that's a valid cast removal but I decided
to keep it for semantic reason.

Same as:

@@ -2277,7 +2277,7 @@ printTrgmColor(StringInfo buf, TrgmColor co)
        else if (co == COLOR_BLANK)
                appendStringInfoChar(buf, 'b');
        else
-               appendStringInfo(buf, "%d", (int) co);
+               appendStringInfo(buf, "%d", co);

where TrgmColor is "typedef int TrgmColor;"

C)

-  if (((unsigned char *) base)[i] != 0xff)
+  if ((base)[i] != 0xff)

because not safe.

See attached the full list that I decided not to include.
Do you think we should add some of them in the patch? (maybe the ones in
nbtcompare.c for example)

Regards,

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

Attachments:

cast_to_keep.txttext/plain; charset=us-asciiDownload
diff --git a/contrib/file_fdw/file_fdw.c b/contrib/file_fdw/file_fdw.c
index 70564a68b13..50d65418ee8 100644
--- a/contrib/file_fdw/file_fdw.c
+++ b/contrib/file_fdw/file_fdw.c
@@ -1294,7 +1294,7 @@ file_acquire_sample_rows(Relation onerel, int elevel,
 				 * Found a suitable tuple, so save it, replacing one old tuple
 				 * at random
 				 */
-				int			k = (int) (targrows * sampler_random_fract(&rstate.randstate));
+				int			k = (targrows * sampler_random_fract(&rstate.randstate));
 
 				Assert(k >= 0 && k < targrows);
 				heap_freetuple(rows[k]);
diff --git a/contrib/hstore/hstore_gist.c b/contrib/hstore/hstore_gist.c
index 69515dc3d3f..5dc065bcc40 100644
--- a/contrib/hstore/hstore_gist.c
+++ b/contrib/hstore/hstore_gist.c
@@ -37,7 +37,7 @@ typedef char *BITVECP;
 			for (i = 0; i < SIGLENBIT(siglen); i++)
 
 /* beware of multiple evaluation of arguments to these macros! */
-#define GETBYTE(x,i) ( *( (BITVECP)(x) + (int)( (i) / BITBYTE ) ) )
+#define GETBYTE(x,i) ( *( (BITVECP)(x) + ( (i) / BITBYTE ) ) )
 #define GETBITBYTE(x,i) ( (*((char*)(x)) >> (i)) & 0x01 )
 #define CLRBIT(x,i)   GETBYTE(x,i) &= ~( 0x01 << ( (i) % BITBYTE ) )
 #define SETBIT(x,i)   GETBYTE(x,i) |=  ( 0x01 << ( (i) % BITBYTE ) )
@@ -74,7 +74,7 @@ typedef struct
 
 #define GETENTRY(vec,pos) ((GISTTYPE *) DatumGetPointer((vec)->vector[(pos)].key))
 
-#define WISH_F(a,b,c) (double)( -(double)(((a)-(b))*((a)-(b))*((a)-(b)))*(c) )
+#define WISH_F(a,b,c) ( -(double)(((a)-(b))*((a)-(b))*((a)-(b)))*(c) )
 
 /* shorthand for calculating CRC-32 of a single chunk of data. */
 static pg_crc32
@@ -258,7 +258,7 @@ sizebitvec(BITVECP sign, int siglen)
 	LOOPBYTE(siglen)
 	{
 		size += SUMBIT(sign);
-		sign = (BITVECP) (((char *) sign) + 1);
+		sign = ((sign) + 1);
 	}
 	return size;
 }
diff --git a/contrib/ltree/_ltree_gist.c b/contrib/ltree/_ltree_gist.c
index 30d516e60bc..c2d89f24dff 100644
--- a/contrib/ltree/_ltree_gist.c
+++ b/contrib/ltree/_ltree_gist.c
@@ -28,7 +28,7 @@ PG_FUNCTION_INFO_V1(_ltree_gist_options);
 #define GETENTRY(vec,pos) ((ltree_gist *) DatumGetPointer((vec)->vector[(pos)].key))
 #define NEXTVAL(x) ( (ltree*)( (char*)(x) + INTALIGN( VARSIZE(x) ) ) )
 
-#define WISH_F(a,b,c) (double)( -(double)(((a)-(b))*((a)-(b))*((a)-(b)))*(c) )
+#define WISH_F(a,b,c) ( -(double)(((a)-(b))*((a)-(b))*((a)-(b)))*(c) )
 
 
 static void
diff --git a/contrib/ltree/ltree_gist.c b/contrib/ltree/ltree_gist.c
index 932f69bff2d..ba6b46a9d5a 100644
--- a/contrib/ltree/ltree_gist.c
+++ b/contrib/ltree/ltree_gist.c
@@ -225,7 +225,7 @@ ltree_union(PG_FUNCTION_ARGS)
 				BITVECP		sc = LTG_SIGN(cur);
 
 				LOOPBYTE(siglen)
-					((unsigned char *) base)[i] |= sc[i];
+					(base)[i] |= sc[i];
 			}
 
 			curtree = LTG_LNODE(cur, siglen);
@@ -242,7 +242,7 @@ ltree_union(PG_FUNCTION_ARGS)
 		isalltrue = true;
 		LOOPBYTE(siglen)
 		{
-			if (((unsigned char *) base)[i] != 0xff)
+			if ((base)[i] != 0xff)
 			{
 				isalltrue = false;
 				break;
@@ -352,7 +352,7 @@ ltree_picksplit(PG_FUNCTION_ARGS)
 					BITVECP		sc = LTG_SIGN(lu);
 
 					LOOPBYTE(siglen)
-						((unsigned char *) ls)[i] |= sc[i];
+						(ls)[i] |= sc[i];
 				}
 			}
 		}
@@ -373,7 +373,7 @@ ltree_picksplit(PG_FUNCTION_ARGS)
 					BITVECP		sc = LTG_SIGN(lu);
 
 					LOOPBYTE(siglen)
-						((unsigned char *) rs)[i] |= sc[i];
+						(rs)[i] |= sc[i];
 				}
 			}
 		}
@@ -384,7 +384,7 @@ ltree_picksplit(PG_FUNCTION_ARGS)
 		lisat = true;
 		LOOPBYTE(siglen)
 		{
-			if (((unsigned char *) ls)[i] != 0xff)
+			if ((ls)[i] != 0xff)
 			{
 				lisat = false;
 				break;
@@ -397,7 +397,7 @@ ltree_picksplit(PG_FUNCTION_ARGS)
 		risat = true;
 		LOOPBYTE(siglen)
 		{
-			if (((unsigned char *) rs)[i] != 0xff)
+			if ((rs)[i] != 0xff)
 			{
 				risat = false;
 				break;
diff --git a/contrib/pg_trgm/trgm_gist.c b/contrib/pg_trgm/trgm_gist.c
index 5ba895217b0..a41fe269c0b 100644
--- a/contrib/pg_trgm/trgm_gist.c
+++ b/contrib/pg_trgm/trgm_gist.c
@@ -727,7 +727,7 @@ gtrgm_penalty(PG_FUNCTION_ARGS)
 			cache = newcache;
 		}
 
-		sign = (BITVECP) cache;
+		sign = cache;
 
 		if (ISALLTRUE(origval))
 			*penalty = ((float) (SIGLENBIT(siglen) - sizebitvec(sign, siglen))) / (float) (SIGLENBIT(siglen) + 1);
@@ -758,7 +758,7 @@ fillcache(CACHESIGN *item, TRGM *key, BITVECP sign, int siglen)
 		memcpy(item->sign, GETSIGN(key), siglen);
 }
 
-#define WISH_F(a,b,c) (double)( -(double)(((a)-(b))*((a)-(b))*((a)-(b)))*(c) )
+#define WISH_F(a,b,c) ( -(double)(((a)-(b))*((a)-(b))*((a)-(b)))*(c) )
 typedef struct
 {
 	OffsetNumber pos;
diff --git a/contrib/pg_trgm/trgm_regexp.c b/contrib/pg_trgm/trgm_regexp.c
index 149f9eb259c..9ab251d8878 100644
--- a/contrib/pg_trgm/trgm_regexp.c
+++ b/contrib/pg_trgm/trgm_regexp.c
@@ -2277,7 +2277,7 @@ printTrgmColor(StringInfo buf, TrgmColor co)
 	else if (co == COLOR_BLANK)
 		appendStringInfoChar(buf, 'b');
 	else
-		appendStringInfo(buf, "%d", (int) co);
+		appendStringInfo(buf, "%d", co);
 }
 
 /*
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 06b52c65300..2ffe836867d 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -5334,7 +5334,7 @@ analyze_row_processor(PGresult *res, int row, PgFdwAnalyzeState *astate)
 		if (astate->rowstoskip <= 0)
 		{
 			/* Choose a random reservoir element to replace. */
-			pos = (int) (targrows * sampler_random_fract(&astate->rstate.randstate));
+			pos = (targrows * sampler_random_fract(&astate->rstate.randstate));
 			Assert(pos >= 0 && pos < targrows);
 			heap_freetuple(astate->rows[pos]);
 		}
diff --git a/contrib/tsm_system_rows/tsm_system_rows.c b/contrib/tsm_system_rows/tsm_system_rows.c
index f401efa2131..1ebcd1d86d6 100644
--- a/contrib/tsm_system_rows/tsm_system_rows.c
+++ b/contrib/tsm_system_rows/tsm_system_rows.c
@@ -335,7 +335,7 @@ random_relative_prime(uint32 n, pg_prng_state *randstate)
 	do
 	{
 		CHECK_FOR_INTERRUPTS();
-		r = (uint32) (sampler_random_fract(randstate) * n);
+		r = (sampler_random_fract(randstate) * n);
 	} while (r == 0 || gcd(r, n) > 1);
 
 	return r;
diff --git a/contrib/tsm_system_time/tsm_system_time.c b/contrib/tsm_system_time/tsm_system_time.c
index c9c71d8c3af..361c92267a0 100644
--- a/contrib/tsm_system_time/tsm_system_time.c
+++ b/contrib/tsm_system_time/tsm_system_time.c
@@ -348,7 +348,7 @@ random_relative_prime(uint32 n, pg_prng_state *randstate)
 	do
 	{
 		CHECK_FOR_INTERRUPTS();
-		r = (uint32) (sampler_random_fract(randstate) * n);
+		r = (sampler_random_fract(randstate) * n);
 	} while (r == 0 || gcd(r, n) > 1);
 
 	return r;
diff --git a/src/backend/access/nbtree/nbtcompare.c b/src/backend/access/nbtree/nbtcompare.c
index 188c27b4925..bcd3b24de7f 100644
--- a/src/backend/access/nbtree/nbtcompare.c
+++ b/src/backend/access/nbtree/nbtcompare.c
@@ -545,7 +545,7 @@ char_decrement(Relation rel, Datum existing, bool *underflow)
 	}
 
 	*underflow = false;
-	return CharGetDatum((uint8) cexisting - 1);
+	return CharGetDatum(cexisting - 1);
 }
 
 static Datum
@@ -561,7 +561,7 @@ char_increment(Relation rel, Datum existing, bool *overflow)
 	}
 
 	*overflow = false;
-	return CharGetDatum((uint8) cexisting + 1);
+	return CharGetDatum(cexisting + 1);
 }
 
 Datum
diff --git a/src/backend/access/spgist/spgtextproc.c b/src/backend/access/spgist/spgtextproc.c
index 91f4ab260c2..e5796fb479d 100644
--- a/src/backend/access/spgist/spgtextproc.c
+++ b/src/backend/access/spgist/spgtextproc.c
@@ -67,7 +67,7 @@
  * choosing a max prefix size of 32 bytes when BLCKSZ is configured smaller
  * than default.
  */
-#define SPGIST_MAX_PREFIX_LENGTH	Max((int) (BLCKSZ - 258 * 16 - 100), 32)
+#define SPGIST_MAX_PREFIX_LENGTH	Max((BLCKSZ - 258 * 16 - 100), 32)
 
 /*
  * Strategy for collation aware operator on text is equal to btree strategy
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index 25089fae3e0..8dc7c9398bf 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -1287,7 +1287,7 @@ acquire_sample_rows(Relation onerel, int elevel,
 					 * Found a suitable tuple, so save it, replacing one old
 					 * tuple at random
 					 */
-					int			k = (int) (targrows * sampler_random_fract(&rstate.randstate));
+					int			k = (targrows * sampler_random_fract(&rstate.randstate));
 
 					Assert(k >= 0 && k < targrows);
 					heap_freetuple(rows[k]);
diff --git a/src/backend/executor/execGrouping.c b/src/backend/executor/execGrouping.c
index 8b64a625ca5..c295dd94801 100644
--- a/src/backend/executor/execGrouping.c
+++ b/src/backend/executor/execGrouping.c
@@ -360,7 +360,7 @@ EstimateTupleHashTableSpace(double nentries,
 		return SIZE_MAX;
 
 	/* We don't bother estimating size of the miscellaneous overhead data */
-	return (Size) (sh_space + tuples_space);
+	return (sh_space + tuples_space);
 }
 
 /*
diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c
index 25f739a6a17..170b6b9e3c1 100644
--- a/src/backend/libpq/pqcomm.c
+++ b/src/backend/libpq/pqcomm.c
@@ -456,7 +456,7 @@ ListenServerPort(int family, const char *hostName, unsigned short portNumber,
 			ereport(LOG,
 					(errmsg("Unix-domain socket path \"%s\" is too long (maximum %d bytes)",
 							unixSocketPath,
-							(int) (UNIXSOCK_PATH_BUFLEN - 1))));
+							(UNIXSOCK_PATH_BUFLEN - 1))));
 			return STATUS_ERROR;
 		}
 		if (Lock_AF_UNIX(unixSocketDir, unixSocketPath) != STATUS_OK)
diff --git a/src/backend/nodes/bitmapset.c b/src/backend/nodes/bitmapset.c
index b4ecf0b0390..d6de78482c7 100644
--- a/src/backend/nodes/bitmapset.c
+++ b/src/backend/nodes/bitmapset.c
@@ -1073,13 +1073,13 @@ bms_add_range(Bitmapset *a, int lower, int upper)
 	 */
 	if (lwordnum == uwordnum)
 	{
-		a->words[lwordnum] |= ~(bitmapword) (((bitmapword) 1 << lbitnum) - 1)
+		a->words[lwordnum] |= ~(((bitmapword) 1 << lbitnum) - 1)
 			& (~(bitmapword) 0) >> ushiftbits;
 	}
 	else
 	{
 		/* turn on lbitnum and all bits left of it */
-		a->words[wordnum++] |= ~(bitmapword) (((bitmapword) 1 << lbitnum) - 1);
+		a->words[wordnum++] |= ~(((bitmapword) 1 << lbitnum) - 1);
 
 		/* turn on all bits for any intermediate words */
 		while (wordnum < uwordnum)
diff --git a/src/backend/optimizer/geqo/geqo_main.c b/src/backend/optimizer/geqo/geqo_main.c
index 0064556087a..be65da2b002 100644
--- a/src/backend/optimizer/geqo/geqo_main.c
+++ b/src/backend/optimizer/geqo/geqo_main.c
@@ -244,7 +244,7 @@ geqo(PlannerInfo *root, int number_of_rels, List *initial_rels)
 #if defined(GEQO_DEBUG)
 	if (edge_failures != 0)
 		elog(LOG, "[GEQO] failures: %d, average: %d",
-			 edge_failures, (int) number_generations / edge_failures);
+			 edge_failures, number_generations / edge_failures);
 	else
 		elog(LOG, "[GEQO] no edge failures detected");
 #else
diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c
index 50c2edec1f6..1b17c69b4d2 100644
--- a/src/backend/postmaster/syslogger.c
+++ b/src/backend/postmaster/syslogger.c
@@ -883,7 +883,7 @@ process_pipe_input(char *logbuffer, int *bytes_in_logbuffer)
 	int			dest = LOG_DESTINATION_STDERR;
 
 	/* While we have enough for a header, process data... */
-	while (count >= (int) (offsetof(PipeProtoHeader, data) + 1))
+	while (count >= (offsetof(PipeProtoHeader, data) + 1))
 	{
 		PipeProtoHeader p;
 		int			chunklen;
diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c
index e3f335a8340..cd19dd7316d 100644
--- a/src/backend/storage/smgr/md.c
+++ b/src/backend/storage/smgr/md.c
@@ -132,7 +132,7 @@ static MemoryContext MdCxt;		/* context for all MdfdVec objects */
 #define MD_PATH_STR_MAXLEN \
 	(\
 		REL_PATH_STR_MAXLEN \
-		+ sizeof((char)'.') \
+		+ sizeof('.') \
 		+ SEGMENT_CHARS \
 	)
 typedef struct MdPathStr
diff --git a/src/backend/storage/sync/sync.c b/src/backend/storage/sync/sync.c
index fc16db90133..e3cab800f5a 100644
--- a/src/backend/storage/sync/sync.c
+++ b/src/backend/storage/sync/sync.c
@@ -374,7 +374,7 @@ ProcessSyncRequests(void)
 			continue;
 
 		/* Else assert we haven't missed it */
-		Assert((CycleCtr) (entry->cycle_ctr + 1) == sync_cycle_ctr);
+		Assert((entry->cycle_ctr + 1) == sync_cycle_ctr);
 
 		/*
 		 * If fsync is off then we don't have to bother opening the file at
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 7dd75a490aa..702c3d16691 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -303,7 +303,7 @@ InteractiveBackend(StringInfo inBuf)
 	 */
 
 	/* Add '\0' to make it look the same as message case. */
-	appendStringInfoChar(inBuf, (char) '\0');
+	appendStringInfoChar(inBuf, '\0');
 
 	/*
 	 * if the query echo flag was given, print the query..
diff --git a/src/backend/utils/adt/like.c b/src/backend/utils/adt/like.c
index 4216ac17f43..32cfe6310c2 100644
--- a/src/backend/utils/adt/like.c
+++ b/src/backend/utils/adt/like.c
@@ -454,5 +454,5 @@ like_escape_bytea(PG_FUNCTION_ARGS)
 	bytea	   *esc = PG_GETARG_BYTEA_PP(1);
 	bytea	   *result = SB_do_like_escape((text *) pat, (text *) esc);
 
-	PG_RETURN_BYTEA_P((bytea *) result);
+	PG_RETURN_BYTEA_P(result);
 }
diff --git a/src/backend/utils/adt/numutils.c b/src/backend/utils/adt/numutils.c
index 3bf30774a0c..f468bc2cd7e 100644
--- a/src/backend/utils/adt/numutils.c
+++ b/src/backend/utils/adt/numutils.c
@@ -1102,7 +1102,7 @@ pg_ultoa_n(uint32 value, char *a)
 	}
 	else
 	{
-		*a = (char) ('0' + value);
+		*a = ('0' + value);
 	}
 
 	return olength;
@@ -1211,7 +1211,7 @@ pg_ulltoa_n(uint64 value, char *a)
 		memcpy(pos - 2, DIGIT_TABLE + c, 2);
 	}
 	else
-		*a = (char) ('0' + value2);
+		*a = ('0' + value2);
 
 	return olength;
 }
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 3d98d064a94..7aaf1ee1f16 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1446,7 +1446,7 @@ pgstat_get_io_time_index(IOOp io_op)
 static inline double
 pg_stat_us_to_ms(PgStat_Counter val_ms)
 {
-	return val_ms * (double) 0.001;
+	return val_ms * 0.001;
 }
 
 /*
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 540aa9628d7..53d96cbea50 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -5456,7 +5456,7 @@ convert_timevalue_to_scalar(Datum value, Oid typid, bool *failure)
 				TimeTzADT  *timetz = DatumGetTimeTzADTP(value);
 
 				/* use GMT-equivalent time */
-				return (double) (timetz->time + (timetz->zone * 1000000.0));
+				return (timetz->time + (timetz->zone * 1000000.0));
 			}
 	}
 
diff --git a/src/backend/utils/adt/tsgistidx.c b/src/backend/utils/adt/tsgistidx.c
index 935187b37c7..23fca62c199 100644
--- a/src/backend/utils/adt/tsgistidx.c
+++ b/src/backend/utils/adt/tsgistidx.c
@@ -575,7 +575,7 @@ fillcache(CACHESIGN *item, SignTSVector *key, int siglen)
 		memcpy(item->sign, GETSIGN(key), siglen);
 }
 
-#define WISH_F(a,b,c) (double)( -(double)(((a)-(b))*((a)-(b))*((a)-(b)))*(c) )
+#define WISH_F(a,b,c) ( -(double)(((a)-(b))*((a)-(b))*((a)-(b)))*(c) )
 typedef struct
 {
 	OffsetNumber pos;
diff --git a/src/backend/utils/adt/tsquery_gist.c b/src/backend/utils/adt/tsquery_gist.c
index f7f94c1c760..ec7da50fc67 100644
--- a/src/backend/utils/adt/tsquery_gist.c
+++ b/src/backend/utils/adt/tsquery_gist.c
@@ -161,7 +161,7 @@ comparecost(const void *a, const void *b)
 					  ((const SPLITCOST *) b)->cost);
 }
 
-#define WISH_F(a,b,c) (double)( -(double)(((a)-(b))*((a)-(b))*((a)-(b)))*(c) )
+#define WISH_F(a,b,c) ( -(double)(((a)-(b))*((a)-(b))*((a)-(b)))*(c) )
 
 Datum
 gtsquery_picksplit(PG_FUNCTION_ARGS)
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 29643c51439..bd86de0a293 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -2703,7 +2703,7 @@ get_formatted_log_time(void)
 				pg_localtime(&stamp_time, log_timezone));
 
 	/* 'paste' milliseconds into place... */
-	sprintf(msbuf, ".%03d", (int) (saved_timeval.tv_usec / 1000));
+	sprintf(msbuf, ".%03d", (saved_timeval.tv_usec / 1000));
 	memcpy(formatted_log_time + 19, msbuf, 4);
 
 	return formatted_log_time;
@@ -3046,7 +3046,7 @@ log_status_format(StringInfo buf, const char *format, ErrorData *edata)
 
 					snprintf(strfbuf, sizeof(strfbuf), "%ld.%03d",
 							 (long) saved_timeval.tv_sec,
-							 (int) (saved_timeval.tv_usec / 1000));
+							 (saved_timeval.tv_usec / 1000));
 
 					if (padding != 0)
 						appendStringInfo(buf, "%*s", padding, strfbuf);
diff --git a/src/backend/utils/mb/conversion_procs/euc_tw_and_big5/big5.c b/src/backend/utils/mb/conversion_procs/euc_tw_and_big5/big5.c
index 68f76aa8cb8..abef1f22bb4 100644
--- a/src/backend/utils/mb/conversion_procs/euc_tw_and_big5/big5.c
+++ b/src/backend/utils/mb/conversion_procs/euc_tw_and_big5/big5.c
@@ -264,7 +264,7 @@ static unsigned short BinarySearchRange
 				 * Its radix is 0x5e. But there is no distance bias like big5.
 				 */
 				distance = tmp * 0x5e
-					+ ((int) (code & 0x00ff) - (int) (array[mid].code & 0x00ff));
+					+ ((code & 0x00ff) - (array[mid].code & 0x00ff));
 
 				/*
 				 * NOTE: Similar to big5 to cns conversion, we extract
diff --git a/src/backend/utils/mb/wstrcmp.c b/src/backend/utils/mb/wstrcmp.c
index dad3ae023a3..f16a2d47252 100644
--- a/src/backend/utils/mb/wstrcmp.c
+++ b/src/backend/utils/mb/wstrcmp.c
@@ -43,5 +43,5 @@ pg_char_and_wchar_strcmp(const char *s1, const pg_wchar *s2)
 	while ((pg_wchar) *s1 == *s2++)
 		if (*s1++ == 0)
 			return 0;
-	return *(const unsigned char *) s1 - *(const pg_wchar *) (s2 - 1);
+	return *(const unsigned char *) s1 - *(s2 - 1);
 }
diff --git a/src/backend/utils/mmgr/aset.c b/src/backend/utils/mmgr/aset.c
index bcd09c07533..bce86fcd304 100644
--- a/src/backend/utils/mmgr/aset.c
+++ b/src/backend/utils/mmgr/aset.c
@@ -517,7 +517,7 @@ AllocSetContextCreateInternal(MemoryContext parent,
 	 */
 	set->allocChunkLimit = ALLOC_CHUNK_LIMIT;
 	while ((Size) (set->allocChunkLimit + ALLOC_CHUNKHDRSZ) >
-		   (Size) ((maxBlockSize - ALLOC_BLOCKHDRSZ) / ALLOC_CHUNK_FRACTION))
+		   ((maxBlockSize - ALLOC_BLOCKHDRSZ) / ALLOC_CHUNK_FRACTION))
 		set->allocChunkLimit >>= 1;
 
 	/* Finally, do the type-independent part of context creation */
diff --git a/src/backend/utils/mmgr/bump.c b/src/backend/utils/mmgr/bump.c
index e60ec94e139..dd4bb93ff81 100644
--- a/src/backend/utils/mmgr/bump.c
+++ b/src/backend/utils/mmgr/bump.c
@@ -228,7 +228,7 @@ BumpContextCreate(MemoryContext parent, const char *name, Size minContextSize,
 	 */
 	set->allocChunkLimit = Min(maxBlockSize, MEMORYCHUNK_MAX_VALUE);
 	while ((Size) (set->allocChunkLimit + Bump_CHUNKHDRSZ) >
-		   (Size) ((Size) (maxBlockSize - Bump_BLOCKHDRSZ) / Bump_CHUNK_FRACTION))
+		   ((maxBlockSize - Bump_BLOCKHDRSZ) / Bump_CHUNK_FRACTION))
 		set->allocChunkLimit >>= 1;
 
 	/* Finally, do the type-independent part of context creation */
@@ -626,10 +626,10 @@ BumpBlockFree(BumpContext *set, BumpBlock *block)
 	/* release the block from the list of blocks */
 	dlist_delete(&block->node);
 
-	((MemoryContext) set)->mem_allocated -= ((char *) block->endptr - (char *) block);
+	((MemoryContext) set)->mem_allocated -= (block->endptr - (char *) block);
 
 #ifdef CLOBBER_FREED_MEMORY
-	wipe_mem(block, ((char *) block->endptr - (char *) block));
+	wipe_mem(block, (block->endptr - (char *) block));
 #endif
 
 	/* As in aset.c, free block-header vchunks explicitly */
diff --git a/src/backend/utils/mmgr/generation.c b/src/backend/utils/mmgr/generation.c
index f6203501956..c9960573ea1 100644
--- a/src/backend/utils/mmgr/generation.c
+++ b/src/backend/utils/mmgr/generation.c
@@ -263,7 +263,7 @@ GenerationContextCreate(MemoryContext parent,
 	 */
 	set->allocChunkLimit = Min(maxBlockSize, MEMORYCHUNK_MAX_VALUE);
 	while ((Size) (set->allocChunkLimit + Generation_CHUNKHDRSZ) >
-		   (Size) ((Size) (maxBlockSize - Generation_BLOCKHDRSZ) / Generation_CHUNK_FRACTION))
+		   ((maxBlockSize - Generation_BLOCKHDRSZ) / Generation_CHUNK_FRACTION))
 		set->allocChunkLimit >>= 1;
 
 	/* Finally, do the type-independent part of context creation */
diff --git a/src/bin/pg_basebackup/walmethods.c b/src/bin/pg_basebackup/walmethods.c
index eaaabc5f374..8a625481aa2 100644
--- a/src/bin/pg_basebackup/walmethods.c
+++ b/src/bin/pg_basebackup/walmethods.c
@@ -644,7 +644,7 @@ CreateWalDirectoryMethod(const char *basedir,
 	DirectoryMethodData *wwmethod;
 
 	wwmethod = pg_malloc0(sizeof(DirectoryMethodData));
-	*((const WalWriteMethodOps **) &wwmethod->base.ops) =
+	*(&wwmethod->base.ops) =
 		&WalDirectoryMethodOps;
 	wwmethod->base.compression_algorithm = compression_algorithm;
 	wwmethod->base.compression_level = compression_level;
@@ -1361,7 +1361,7 @@ CreateWalTarMethod(const char *tarbase,
 		".tar.gz" : ".tar";
 
 	wwmethod = pg_malloc0(sizeof(TarMethodData));
-	*((const WalWriteMethodOps **) &wwmethod->base.ops) =
+	*(&wwmethod->base.ops) =
 		&WalTarMethodOps;
 	wwmethod->base.compression_algorithm = compression_algorithm;
 	wwmethod->base.compression_level = compression_level;
diff --git a/src/bin/pg_upgrade/pg_upgrade.c b/src/bin/pg_upgrade/pg_upgrade.c
index 490e98fa26f..e4be03a3d36 100644
--- a/src/bin/pg_upgrade/pg_upgrade.c
+++ b/src/bin/pg_upgrade/pg_upgrade.c
@@ -295,7 +295,7 @@ make_outputdirs(char *pgdata)
 	strftime(timebuf, sizeof(timebuf), "%Y%m%dT%H%M%S", localtime(&tt));
 	/* append milliseconds */
 	snprintf(timebuf + strlen(timebuf), sizeof(timebuf) - strlen(timebuf),
-			 ".%03d", (int) (time.tv_usec / 1000));
+			 ".%03d", (time.tv_usec / 1000));
 	log_opts.basedir = (char *) pg_malloc0(MAXPGPATH);
 	len = snprintf(log_opts.basedir, MAXPGPATH, "%s/%s", log_opts.rootdir,
 				   timebuf);
diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c
index 68774a59efd..fb515181a66 100644
--- a/src/bin/pgbench/pgbench.c
+++ b/src/bin/pgbench/pgbench.c
@@ -1120,7 +1120,7 @@ getExponentialRand(pg_prng_state *state, int64 min, int64 max,
 	Assert((1.0 - cut) != 0.0);
 	rand = -log(cut + (1.0 - cut) * uniform) / parameter;
 	/* return int64 random number within between min and max */
-	return min + (int64) ((max - min + 1) * rand);
+	return min + ((max - min + 1) * rand);
 }
 
 /* random number generator: gaussian distribution from min to max inclusive */
@@ -1156,7 +1156,7 @@ getGaussianRand(pg_prng_state *state, int64 min, int64 max,
 	rand = (stdev + parameter) / (parameter * 2.0);
 
 	/* return int64 random number within between min and max */
-	return min + (int64) ((max - min + 1) * rand);
+	return min + ((max - min + 1) * rand);
 }
 
 /*
diff --git a/src/common/d2s.c b/src/common/d2s.c
index 5322c465d53..e0ac9d36c57 100644
--- a/src/common/d2s.c
+++ b/src/common/d2s.c
@@ -736,7 +736,7 @@ to_chars_df(const floating_decimal_64 v, const uint32 olength, char *const resul
 	}
 	else
 	{
-		result[index] = (char) ('0' + output2);
+		result[index] = ('0' + output2);
 	}
 
 	if (index == 1)
@@ -917,7 +917,7 @@ to_chars(floating_decimal_64 v, const bool sign, char *const result)
 	}
 	else
 	{
-		result[index] = (char) ('0' + output2);
+		result[index] = ('0' + output2);
 	}
 
 	/* Print decimal point if needed. */
@@ -946,7 +946,7 @@ to_chars(floating_decimal_64 v, const bool sign, char *const result)
 		const int32 c = exp % 10;
 
 		memcpy(result + index, DIGIT_TABLE + 2 * (exp / 10), 2);
-		result[index + 2] = (char) ('0' + c);
+		result[index + 2] = ('0' + c);
 		index += 3;
 	}
 	else
diff --git a/src/common/f2s.c b/src/common/f2s.c
index a239a8765b0..c94d2261511 100644
--- a/src/common/f2s.c
+++ b/src/common/f2s.c
@@ -517,7 +517,7 @@ to_chars_f(const floating_decimal_32 v, const uint32 olength, char *const result
 	}
 	else
 	{
-		result[index] = (char) ('0' + output);
+		result[index] = ('0' + output);
 	}
 
 	if (index == 1)
@@ -655,7 +655,7 @@ to_chars(const floating_decimal_32 v, const bool sign, char *const result)
 	}
 	else
 	{
-		result[index] = (char) ('0' + output);
+		result[index] = ('0' + output);
 	}
 
 	/* Print decimal point if needed. */
diff --git a/src/interfaces/ecpg/compatlib/informix.c b/src/interfaces/ecpg/compatlib/informix.c
index ca11a81f1bc..5e546950820 100644
--- a/src/interfaces/ecpg/compatlib/informix.c
+++ b/src/interfaces/ecpg/compatlib/informix.c
@@ -383,7 +383,7 @@ dectoasc(decimal *np, char *cp, int len, int right)
 	char	   *str;
 	numeric    *nres;
 
-	rsetnull(CSTRINGTYPE, (char *) cp);
+	rsetnull(CSTRINGTYPE, cp);
 	if (risnull(CDECIMALTYPE, (char *) np))
 		return 0;
 
@@ -410,7 +410,7 @@ dectoasc(decimal *np, char *cp, int len, int right)
 	 * TODO: have to take care of len here and create exponential notation if
 	 * necessary
 	 */
-	if ((int) (strlen(str) + 1) > len)
+	if ((strlen(str) + 1) > len)
 	{
 		if (len > 1)
 		{
diff --git a/src/interfaces/ecpg/ecpglib/data.c b/src/interfaces/ecpg/ecpglib/data.c
index d5d40f7b654..b5b9dd7412f 100644
--- a/src/interfaces/ecpg/ecpglib/data.c
+++ b/src/interfaces/ecpg/ecpglib/data.c
@@ -390,7 +390,7 @@ ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno,
 							*((int *) (var + offset * act_tuple)) = (int) res;
 							break;
 						case ECPGt_long:
-							*((long *) (var + offset * act_tuple)) = (long) res;
+							*((long *) (var + offset * act_tuple)) = res;
 							break;
 						default:
 							/* Cannot happen */
@@ -419,7 +419,7 @@ ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno,
 							*((unsigned int *) (var + offset * act_tuple)) = (unsigned int) ures;
 							break;
 						case ECPGt_unsigned_long:
-							*((unsigned long *) (var + offset * act_tuple)) = (unsigned long) ures;
+							*((unsigned long *) (var + offset * act_tuple)) = ures;
 							break;
 						default:
 							/* Cannot happen */
@@ -557,7 +557,7 @@ ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno,
 				case ECPGt_unsigned_char:
 				case ECPGt_string:
 					{
-						char	   *str = (char *) (var + offset * act_tuple);
+						char	   *str = (var + offset * act_tuple);
 
 						/*
 						 * If varcharsize is unknown and the offset is that of
diff --git a/src/interfaces/ecpg/pgtypeslib/dt_common.c b/src/interfaces/ecpg/pgtypeslib/dt_common.c
index c4119ab7932..fe960edc236 100644
--- a/src/interfaces/ecpg/pgtypeslib/dt_common.c
+++ b/src/interfaces/ecpg/pgtypeslib/dt_common.c
@@ -892,7 +892,7 @@ EncodeDateTime(struct tm *tm, fsec_t fsec, bool print_tz, int tz, const char *tz
 			/* Backward-compatible with traditional Postgres abstime dates */
 
 			day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
-			tm->tm_wday = (int) ((day + date2j(2000, 1, 1) + 1) % 7);
+			tm->tm_wday = ((day + date2j(2000, 1, 1) + 1) % 7);
 
 			memcpy(str, days[tm->tm_wday], 3);
 			strcpy(str + 3, " ");
diff --git a/src/interfaces/ecpg/test/expected/sql-desc.c b/src/interfaces/ecpg/test/expected/sql-desc.c
index bdd12a506be..ecf0bd60e2a 100644
--- a/src/interfaces/ecpg/test/expected/sql-desc.c
+++ b/src/interfaces/ecpg/test/expected/sql-desc.c
@@ -280,7 +280,7 @@ if (sqlca.sqlcode < 0) sqlprint();}
 #line 65 "desc.pgc"
 
 
-	{ ECPGset_desc_header(__LINE__, "indesc", (int)(1));
+	{ ECPGset_desc_header(__LINE__, "indesc", (1));
 
 #line 67 "desc.pgc"
 
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index c3a2448dce5..b87774334ce 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -3096,7 +3096,7 @@ keep_going:						/* We will come back to here until there is
 				{
 					libpq_append_conn_error(conn, "Unix-domain socket path \"%s\" is too long (maximum %d bytes)",
 											portstr,
-											(int) (UNIXSOCK_PATH_BUFLEN - 1));
+											(UNIXSOCK_PATH_BUFLEN - 1));
 					goto keep_going;
 				}
 
diff --git a/src/test/isolation/isolation_main.c b/src/test/isolation/isolation_main.c
index a13f9cdcaf7..f9b165c5cf4 100644
--- a/src/test/isolation/isolation_main.c
+++ b/src/test/isolation/isolation_main.c
@@ -125,7 +125,7 @@ isolation_init(int argc, char **argv)
 	if (argv0_len >= MAXPGPATH)
 	{
 		fprintf(stderr, _("path for isolationtester executable is longer than %d bytes\n"),
-				(int) (MAXPGPATH - 1));
+				(MAXPGPATH - 1));
 		exit(2);
 	}
 
diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c
index 56cc0567b1c..bad6c576b2f 100644
--- a/src/test/regress/regress.c
+++ b/src/test/regress/regress.c
@@ -1082,7 +1082,7 @@ test_enc_conversion(PG_FUNCTION_ARGS)
 					 errdetail("String of %d bytes is too long for encoding conversion.",
 							   (int) srclen)));
 
-		dstsize = (Size) srclen * MAX_CONVERSION_GROWTH + 1;
+		dstsize = srclen * MAX_CONVERSION_GROWTH + 1;
 		dst = MemoryContextAlloc(CurrentMemoryContext, dstsize);
 
 		/* perform conversion */
diff --git a/src/timezone/localtime.c b/src/timezone/localtime.c
index 20147f1a2c2..fb68594b868 100644
--- a/src/timezone/localtime.c
+++ b/src/timezone/localtime.c
@@ -1522,7 +1522,7 @@ timesub(const pg_time_t *timep, int_fast32_t offset,
 	ip = mon_lengths[isleap(y)];
 	for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
 		idays -= ip[tmp->tm_mon];
-	tmp->tm_mday = (int) (idays + 1);
+	tmp->tm_mday = (idays + 1);
 	tmp->tm_isdst = 0;
 	tmp->tm_gmtoff = offset;
 	return tmp;
diff --git a/src/timezone/zic.c b/src/timezone/zic.c
index a8c1de9910d..1b4f3017f12 100644
--- a/src/timezone/zic.c
+++ b/src/timezone/zic.c
@@ -3891,7 +3891,7 @@ will not work with pre-2004 versions of zic"));
 		return min_time;
 	if (dayoff > max_time / SECSPERDAY)
 		return max_time;
-	t = (zic_t) dayoff * SECSPERDAY;
+	t = dayoff * SECSPERDAY;
 	return tadd(t, rp->r_tod);
 }
 
#5Bertrand Drouvot
bertranddrouvot.pg@gmail.com
In reply to: Jacob Champion (#3)
Re: Remove useless casting to the same type

Hi,

On Mon, Nov 24, 2025 at 03:18:00PM -0800, Jacob Champion wrote:

On Mon, Nov 24, 2025 at 2:26 AM Bertrand Drouvot
<bertranddrouvot.pg@gmail.com> wrote:

Attached is a patch to $SUBJECT.

--- a/src/backend/access/gin/gindatapage.c
+++ b/src/backend/access/gin/gindatapage.c
@@ -607,11 +607,11 @@ dataBeginPlaceToPageLeaf(GinBtree btree, Buffer buf, GinBtreeStack *stack,
if (append)
elog(DEBUG2, "appended %d new items to block %u; %d bytes (%d to go)",
- maxitems, BufferGetBlockNumber(buf), (int) leaf->lsize,
+ maxitems, BufferGetBlockNumber(buf), leaf->lsize,
items->nitem - items->curitem - maxitems);

Hm. How do we feel, as a group, about superstitious casts in variadic
calls? I don't feel like they're in the same class as the other fixes.

Argument for: it's nice to know at a glance that a printf() invocation
won't corrupt something horribly, especially if I'm quickly scanning
code during a CVE analysis, and especially if the variable is named as
if it could maybe be a size_t. Do our compilers warn us well enough
now, in practice?

Argument against: it takes up precious columns and focuses attention
away from other things.

Thanks for looking at it!

I think that the variadic calls in the patch are related to functions that
can benefits from -Wformat. Let's focus on those: with the cast one would need
to verify 3 things: variable type, cast and format specifier.
Without the cast then only 2 things and the compiler can verify these match via
-Wformat warnings.

With the cast, the compiler only checks that the cast result matches the format,
not whether the cast itself is correct, so I'm in favor of removing the cast,
thoughts?

Like the fact that (items->nitem -
items->curitem - maxitems) is unsigned and printed as signed here. :D

Nice catch! ;-)

Maybe we should make the code compile cleanly under
-Wformat-signedness at some point...

good idea, will give it a try later on outside the context of this patch.

@@ -389,7 +389,7 @@ hash_xlog_split_allocate_page(XLogReaderState *record)

/* extract low and high masks. */
memcpy(&lowmask, data, sizeof(uint32));
- highmask = (uint32 *) ((char *) data + sizeof(uint32));
+ highmask = (uint32 *) (data + sizeof(uint32));

I wonder about these, too. I like knowing what the code does without
having to check the type of `data`. But then later on we do a `data +=
sizeof(uint32) * 2`, so you have to check the type anyway, so... I
don't know.

I think that even with the cast in place, it's good to check the type of data.
Not for the line that follows (i.e: "data += sizeof(uint32) * 2") but to check
that the cast makes sense and does not hide "wrong" pointer manipulation.

So I think that with or without the cast one would need to check. But that feels
more natural to check when there is no cast (as we don't assume that someone
said "I know what I'm doing"). So I'm in favor of removing the cast, thoughts?

+++ b/contrib/fuzzystrmatch/dmetaphone.c
@@ -327,7 +327,7 @@ GetAt(metastring *s, int pos)
if ((pos < 0) || (pos >= s->length))
return '\0';
- return ((char) *(s->str + pos));
+ return *(s->str + pos);

Isn't this just s->str[pos]? Ditto for SetAt(), right afterwards.

Yeah, "*(s->str + pos)" is already used in SetAt() and also in IsVowel(). Instead
of changing those 3, I'd prefer to keep the current change and keep the patch
focus on its intend. We could change those in a dedicated patch afterward if we
feel the need.

Regards,

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

#6David Geier
geidav.pg@gmail.com
In reply to: Bertrand Drouvot (#5)
Re: Remove useless casting to the same type

On 25.11.2025 06:46, Bertrand Drouvot wrote:

I think that the variadic calls in the patch are related to functions that
can benefits from -Wformat. Let's focus on those: with the cast one would need
to verify 3 things: variable type, cast and format specifier.
Without the cast then only 2 things and the compiler can verify these match via
-Wformat warnings.

With the cast, the compiler only checks that the cast result matches the format,
not whether the cast itself is correct, so I'm in favor of removing the cast,
thoughts?

I agree. It's better if we only have the casts in places where we
actually want to change the type before printing.

Another benefit is that one can directly deduct the type from the log /
print statement by looking at the format specifier.

--
David Geier

#7Peter Eisentraut
peter@eisentraut.org
In reply to: Bertrand Drouvot (#5)
1 attachment(s)
Re: Remove useless casting to the same type

On 25.11.25 06:46, Bertrand Drouvot wrote:

@@ -389,7 +389,7 @@ hash_xlog_split_allocate_page(XLogReaderState *record)

/* extract low and high masks. */
memcpy(&lowmask, data, sizeof(uint32));
- highmask = (uint32 *) ((char *) data + sizeof(uint32));
+ highmask = (uint32 *) (data + sizeof(uint32));

I wonder about these, too. I like knowing what the code does without
having to check the type of `data`. But then later on we do a `data +=
sizeof(uint32) * 2`, so you have to check the type anyway, so... I
don't know.

I think that even with the cast in place, it's good to check the type of data.
Not for the line that follows (i.e: "data += sizeof(uint32) * 2") but to check
that the cast makes sense and does not hide "wrong" pointer manipulation.

So I think that with or without the cast one would need to check. But that feels
more natural to check when there is no cast (as we don't assume that someone
said "I know what I'm doing"). So I'm in favor of removing the cast, thoughts?

I think this whole thing could be simplified by overlaying a uint32 over
"data" and just accessing the array fields normally. See attached patch.

Attachments:

0001-Simplify-hash_xlog_split_allocate_page.patch.nocfbottext/plain; charset=UTF-8; name=0001-Simplify-hash_xlog_split_allocate_page.patch.nocfbotDownload
From 01d999144692ce3af845882bbe32754f260281fb Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Fri, 28 Nov 2025 09:05:48 +0100
Subject: [PATCH] Simplify hash_xlog_split_allocate_page()

---
 src/backend/access/hash/hash_xlog.c | 28 ++++++++++------------------
 1 file changed, 10 insertions(+), 18 deletions(-)

diff --git a/src/backend/access/hash/hash_xlog.c b/src/backend/access/hash/hash_xlog.c
index 2a0145f3c9b..fa6b80d3a83 100644
--- a/src/backend/access/hash/hash_xlog.c
+++ b/src/backend/access/hash/hash_xlog.c
@@ -314,8 +314,6 @@ hash_xlog_split_allocate_page(XLogReaderState *record)
 	Buffer		oldbuf;
 	Buffer		newbuf;
 	Buffer		metabuf;
-	Size		datalen PG_USED_FOR_ASSERTS_ONLY;
-	char	   *data;
 	XLogRedoAction action;
 
 	/*
@@ -375,6 +373,8 @@ hash_xlog_split_allocate_page(XLogReaderState *record)
 	{
 		Page		page;
 		HashMetaPage metap;
+		Size		datalen;
+		char	   *data;
 
 		page = BufferGetPage(metabuf);
 		metap = HashPageGetMeta(page);
@@ -384,31 +384,23 @@ hash_xlog_split_allocate_page(XLogReaderState *record)
 
 		if (xlrec->flags & XLH_SPLIT_META_UPDATE_MASKS)
 		{
-			uint32		lowmask;
-			uint32	   *highmask;
-
-			/* extract low and high masks. */
-			memcpy(&lowmask, data, sizeof(uint32));
-			highmask = (uint32 *) ((char *) data + sizeof(uint32));
+			uint32	   *mask_data = (uint32 *) data;
+			uint32		lowmask = mask_data[0];
+			uint32		highmask = mask_data[1];
 
 			/* update metapage */
 			metap->hashm_lowmask = lowmask;
-			metap->hashm_highmask = *highmask;
-
-			data += sizeof(uint32) * 2;
+			metap->hashm_highmask = highmask;
 		}
 
 		if (xlrec->flags & XLH_SPLIT_META_UPDATE_SPLITPOINT)
 		{
-			uint32		ovflpoint;
-			uint32	   *ovflpages;
-
-			/* extract information of overflow pages. */
-			memcpy(&ovflpoint, data, sizeof(uint32));
-			ovflpages = (uint32 *) ((char *) data + sizeof(uint32));
+			uint32	   *ovfl_data = (uint32 *) data;
+			uint32		ovflpoint = ovfl_data[0];
+			uint32		ovflpages = ovfl_data[1];
 
 			/* update metapage */
-			metap->hashm_spares[ovflpoint] = *ovflpages;
+			metap->hashm_spares[ovflpoint] = ovflpages;
 			metap->hashm_ovflpoint = ovflpoint;
 		}
 
-- 
2.52.0

#8Peter Eisentraut
peter@eisentraut.org
In reply to: Bertrand Drouvot (#5)
Re: Remove useless casting to the same type

On 25.11.25 06:46, Bertrand Drouvot wrote:

Hm. How do we feel, as a group, about superstitious casts in variadic
calls? I don't feel like they're in the same class as the other fixes.

Argument for: it's nice to know at a glance that a printf() invocation
won't corrupt something horribly, especially if I'm quickly scanning
code during a CVE analysis, and especially if the variable is named as
if it could maybe be a size_t. Do our compilers warn us well enough
now, in practice?

Argument against: it takes up precious columns and focuses attention
away from other things.

Thanks for looking at it!

I think that the variadic calls in the patch are related to functions that
can benefits from -Wformat. Let's focus on those: with the cast one would need
to verify 3 things: variable type, cast and format specifier.
Without the cast then only 2 things and the compiler can verify these match via
-Wformat warnings.

With the cast, the compiler only checks that the cast result matches the format,
not whether the cast itself is correct, so I'm in favor of removing the cast,
thoughts?

Yes, I think with -Wformat you get approximately the same level of
protection as with a prototype.

Like the fact that (items->nitem -
items->curitem - maxitems) is unsigned and printed as signed here. :D

Nice catch! ;-)

Maybe we should make the code compile cleanly under
-Wformat-signedness at some point...

That would be similar to using -Wsign-conversion with function
prototypes. Maybe a good idea, but we don't use it, and so we shouldn't
expect it for non-prototype invocations either.

#9Peter Eisentraut
peter@eisentraut.org
In reply to: Bertrand Drouvot (#5)
Re: Remove useless casting to the same type

On 25.11.25 06:46, Bertrand Drouvot wrote:

Maybe we should make the code compile cleanly under
-Wformat-signedness at some point...

good idea, will give it a try later on outside the context of this patch.

I test this once in a while and fix the issues that I find. But it's
very picky and you will find difficult to fix problems like the fact
that the signedness of enums is implementation-defined, and so the only
portable fix there would be to add more casts.

I think it could be useful to tighten the source code with respect to
implicit integer conversions, using warnings such as -Wsign-conversion
and -Wconversion as well as -Wformat-signedness. There are surely
hidden overflow or truncation issues similar to CVE-2025-12818 hidden
somewhere. But explicit casts defeat those warnings, so removing
unnecessary casts is a good step on the way there.

#10Bertrand Drouvot
bertranddrouvot.pg@gmail.com
In reply to: Peter Eisentraut (#7)
Re: Remove useless casting to the same type

Hi,

On Fri, Nov 28, 2025 at 09:11:16AM +0100, Peter Eisentraut wrote:

On 25.11.25 06:46, Bertrand Drouvot wrote:

@@ -389,7 +389,7 @@ hash_xlog_split_allocate_page(XLogReaderState *record)

/* extract low and high masks. */
memcpy(&lowmask, data, sizeof(uint32));
- highmask = (uint32 *) ((char *) data + sizeof(uint32));
+ highmask = (uint32 *) (data + sizeof(uint32));

I wonder about these, too. I like knowing what the code does without
having to check the type of `data`. But then later on we do a `data +=
sizeof(uint32) * 2`, so you have to check the type anyway, so... I
don't know.

I think that even with the cast in place, it's good to check the type of data.
Not for the line that follows (i.e: "data += sizeof(uint32) * 2") but to check
that the cast makes sense and does not hide "wrong" pointer manipulation.

So I think that with or without the cast one would need to check. But that feels
more natural to check when there is no cast (as we don't assume that someone
said "I know what I'm doing"). So I'm in favor of removing the cast, thoughts?

I think this whole thing could be simplified by overlaying a uint32 over
"data" and just accessing the array fields normally. See attached patch.

Indeed, that's a nice simplification.

- data += sizeof(uint32) * 2;

Is it safe? I mean could XLH_SPLIT_META_UPDATE_MASKS and XLH_SPLIT_META_UPDATE_SPLITPOINT
be set simultaneously?

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 (#10)
1 attachment(s)
Re: Remove useless casting to the same type

On 28.11.25 10:06, Bertrand Drouvot wrote:

Hi,

On Fri, Nov 28, 2025 at 09:11:16AM +0100, Peter Eisentraut wrote:

On 25.11.25 06:46, Bertrand Drouvot wrote:

@@ -389,7 +389,7 @@ hash_xlog_split_allocate_page(XLogReaderState *record)

/* extract low and high masks. */
memcpy(&lowmask, data, sizeof(uint32));
- highmask = (uint32 *) ((char *) data + sizeof(uint32));
+ highmask = (uint32 *) (data + sizeof(uint32));

I wonder about these, too. I like knowing what the code does without
having to check the type of `data`. But then later on we do a `data +=
sizeof(uint32) * 2`, so you have to check the type anyway, so... I
don't know.

I think that even with the cast in place, it's good to check the type of data.
Not for the line that follows (i.e: "data += sizeof(uint32) * 2") but to check
that the cast makes sense and does not hide "wrong" pointer manipulation.

So I think that with or without the cast one would need to check. But that feels
more natural to check when there is no cast (as we don't assume that someone
said "I know what I'm doing"). So I'm in favor of removing the cast, thoughts?

I think this whole thing could be simplified by overlaying a uint32 over
"data" and just accessing the array fields normally. See attached patch.

Indeed, that's a nice simplification.

- data += sizeof(uint32) * 2;

Is it safe? I mean could XLH_SPLIT_META_UPDATE_MASKS and XLH_SPLIT_META_UPDATE_SPLITPOINT
be set simultaneously?

Yes, that's what was probably intended. But apparently not exercised in
the tests.

So maybe more like this patch.

Attachments:

v2-0001-Simplify-hash_xlog_split_allocate_page.patch.nocfbottext/plain; charset=UTF-8; name=v2-0001-Simplify-hash_xlog_split_allocate_page.patch.nocfbotDownload
From 4d1ade22d4fa45daa5e6e3bfc2c701f9536d0a95 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Fri, 28 Nov 2025 14:18:37 +0100
Subject: [PATCH v2] Simplify hash_xlog_split_allocate_page()

---
 src/backend/access/hash/hash_xlog.c | 30 ++++++++++++-----------------
 1 file changed, 12 insertions(+), 18 deletions(-)

diff --git a/src/backend/access/hash/hash_xlog.c b/src/backend/access/hash/hash_xlog.c
index 2a0145f3c9b..440220dca56 100644
--- a/src/backend/access/hash/hash_xlog.c
+++ b/src/backend/access/hash/hash_xlog.c
@@ -314,8 +314,6 @@ hash_xlog_split_allocate_page(XLogReaderState *record)
 	Buffer		oldbuf;
 	Buffer		newbuf;
 	Buffer		metabuf;
-	Size		datalen PG_USED_FOR_ASSERTS_ONLY;
-	char	   *data;
 	XLogRedoAction action;
 
 	/*
@@ -375,41 +373,37 @@ hash_xlog_split_allocate_page(XLogReaderState *record)
 	{
 		Page		page;
 		HashMetaPage metap;
+		Size		datalen;
+		char	   *data;
+		uint32	   *uidata;
+		int			uidatacount;
 
 		page = BufferGetPage(metabuf);
 		metap = HashPageGetMeta(page);
 		metap->hashm_maxbucket = xlrec->new_bucket;
 
 		data = XLogRecGetBlockData(record, 2, &datalen);
+		uidata = (uint32 *) data;
+		uidatacount = 0;
 
 		if (xlrec->flags & XLH_SPLIT_META_UPDATE_MASKS)
 		{
-			uint32		lowmask;
-			uint32	   *highmask;
-
-			/* extract low and high masks. */
-			memcpy(&lowmask, data, sizeof(uint32));
-			highmask = (uint32 *) ((char *) data + sizeof(uint32));
+			uint32		lowmask = uidata[uidatacount++];
+			uint32		highmask = uidata[uidatacount++];
 
 			/* update metapage */
 			metap->hashm_lowmask = lowmask;
-			metap->hashm_highmask = *highmask;
-
-			data += sizeof(uint32) * 2;
+			metap->hashm_highmask = highmask;
 		}
 
 		if (xlrec->flags & XLH_SPLIT_META_UPDATE_SPLITPOINT)
 		{
-			uint32		ovflpoint;
-			uint32	   *ovflpages;
-
-			/* extract information of overflow pages. */
-			memcpy(&ovflpoint, data, sizeof(uint32));
-			ovflpages = (uint32 *) ((char *) data + sizeof(uint32));
+			uint32		ovflpoint = uidata[uidatacount++];
+			uint32		ovflpages = uidata[uidatacount++];
 
 			/* update metapage */
-			metap->hashm_spares[ovflpoint] = *ovflpages;
 			metap->hashm_ovflpoint = ovflpoint;
+			metap->hashm_spares[ovflpoint] = ovflpages;
 		}
 
 		MarkBufferDirty(metabuf);
-- 
2.52.0

#12Bertrand Drouvot
bertranddrouvot.pg@gmail.com
In reply to: Peter Eisentraut (#11)
Re: Remove useless casting to the same type

Hi,

On Fri, Nov 28, 2025 at 02:20:25PM +0100, Peter Eisentraut wrote:

On 28.11.25 10:06, Bertrand Drouvot wrote:

On Fri, Nov 28, 2025 at 09:11:16AM +0100, Peter Eisentraut wrote:

I think this whole thing could be simplified by overlaying a uint32 over
"data" and just accessing the array fields normally. See attached patch.

Indeed, that's a nice simplification.

- data += sizeof(uint32) * 2;

Is it safe? I mean could XLH_SPLIT_META_UPDATE_MASKS and XLH_SPLIT_META_UPDATE_SPLITPOINT
be set simultaneously?

Yes, that's what was probably intended. But apparently not exercised in the
tests.

So maybe more like this patch.

+   uint32          lowmask = uidata[uidatacount++];
+   uint32          highmask = uidata[uidatacount++];

good idea! That way that's easier to add more branches/flags later if we need
to.

Also, I think that's safe thanks to XLogRecGetBlockData() returning a
MAXALIGNed buffer. Not sure if it's worth to add a comment. I think that a
comment was not needed with the original code as it was using memcpy() instead.

Except for the nit comment remark above, LGTM.

Regards,

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

#13Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Bertrand Drouvot (#5)
Re: Remove useless casting to the same type

On Mon, Nov 24, 2025 at 9:46 PM Bertrand Drouvot
<bertranddrouvot.pg@gmail.com> wrote:

I think that even with the cast in place, it's good to check the type of data.
Not for the line that follows (i.e: "data += sizeof(uint32) * 2") but to check
that the cast makes sense and does not hide "wrong" pointer manipulation.

From a specifier standpoint ("accidentally got rid of const"), yes.
From a pointer math standpoint, `(char *) ptr + offset` has a specific
meaning to me, and I was arguing that hiding that meaning isn't
necessarily useful in all cases.

But! Peter's followup makes this moot. Which is good, and it might
serve as its own blueprint for when we next see a situation like this.

Yeah, "*(s->str + pos)" is already used in SetAt() and also in IsVowel(). Instead
of changing those 3, I'd prefer to keep the current change and keep the patch
focus on its intend. We could change those in a dedicated patch afterward if we
feel the need.

Fine by me. Thanks for this cleanup work!

--Jacob

#14Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Peter Eisentraut (#9)
Re: Remove useless casting to the same type

On Fri, Nov 28, 2025 at 12:41 AM Peter Eisentraut <peter@eisentraut.org> wrote:

I test this once in a while and fix the issues that I find. But it's
very picky and you will find difficult to fix problems like the fact
that the signedness of enums is implementation-defined, and so the only
portable fix there would be to add more casts.

Once you've gotten into that situation, don't you have potential
sign-extension issues during int promotion, which require casts
anyway? It might be nice to fix those up regardless (he said, from his
armchair). But that doesn't seem as pressing as the other potential
problems.

I think it could be useful to tighten the source code with respect to
implicit integer conversions, using warnings such as -Wsign-conversion
and -Wconversion as well as -Wformat-signedness. There are surely
hidden overflow or truncation issues similar to CVE-2025-12818 hidden
somewhere. But explicit casts defeat those warnings, so removing
unnecessary casts is a good step on the way there.

+1. (And your v2 looks good to me.)

--Jacob

#15Peter Eisentraut
peter@eisentraut.org
In reply to: Bertrand Drouvot (#1)
Re: Remove useless casting to the same type

On 24.11.25 11:26, Bertrand Drouvot wrote:

Hi hackers,

Attached is a patch to $SUBJECT.

This is the same kind of idea as 7f798aca1d5 and ef8fe693606, as their presence
could cause risks of hiding actual type mismatches in the future or silently
discarding qualifiers. I think that it also improves readability.

Those have been found with a coccinelle script as:

"
@@
type T;
T E;
@@

- (T)
E
"

which removes casts when it's casting to the same type.

Note that it generated more that what is in the attached. I chose not to remove
some of them (mainly arithmetic ones) to keep the patch focused on what matters
here.

Committed. I made some cosmetic adjustments, to remove line breaks that
are no longer necessary with the shortened lines, and in gbt_num_union()
I kept &out[0] (instead of just out) for consistency with the following
line.

#16Bertrand Drouvot
bertranddrouvot.pg@gmail.com
In reply to: Jacob Champion (#13)
Re: Remove useless casting to the same type

Hi,

On Mon, Dec 01, 2025 at 09:50:43AM -0800, Jacob Champion wrote:

Fine by me.

Thanks for the review!

Thanks for this cleanup work!

That's fun and useful to do!

Regards,

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