Datum as struct

Started by Peter Eisentraut6 months ago16 messages
#1Peter Eisentraut
peter@eisentraut.org
6 attachment(s)

Another draft patch set that I had lying around that was mentioned in [0]/messages/by-id/1749799.1752797397@sss.pgh.pa.us.

The idea is to change Datum to a struct so that you can no longer rely
on it being implicitly convertable to other C types, which enforces use
of proper DatumGet*() and *GetDatum() functions, which might ultimately
help with portability and robustness and the like. (An alternative idea
is to make Datum a union so that you don't need so many casts to begin
with. But this has a lot of the same issues, so it can be considered
implicitly here.)

The first three patches clean up the use of the conversion functions.
Some are missing, some are superfluous, some are used the wrong way
around (!!).

The fourth patch tidies up the use of varatt.h macros. These should
arguably not be used on Datum values but instead be converted with
DatumGetPointer(). This is very similar to the patch that I also
included in the thread "Convert varatt.h macros to static inline
functions" that I just posted.

The fifth patch cleans up some untidy use of hash functions with the
wrong argument type.

The last patch is the actual conversion. As you can see there, and as
was also mentioned in [0]/messages/by-id/1749799.1752797397@sss.pgh.pa.us, it's quite a bit of churn. I'm not seriously
proposing it at this point, but maybe it can serve as a guide for
refactoring some of the interfaces to make the impact smaller, or
something like that.

But I think the patches 0001 through 0005 are useful now.

I tested this against the original patch in [0]/messages/by-id/1749799.1752797397@sss.pgh.pa.us. It fixes some of the
issues discussed there but not all of them.

[0]: /messages/by-id/1749799.1752797397@sss.pgh.pa.us
/messages/by-id/1749799.1752797397@sss.pgh.pa.us

Attachments:

v1-0001-Fix-mixups-of-FooGetDatum-vs.-DatumGetFoo.patchtext/plain; charset=UTF-8; name=v1-0001-Fix-mixups-of-FooGetDatum-vs.-DatumGetFoo.patchDownload
From 94f5a2efea9bc7aa6f6a29d668b6b99fa9689174 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Thu, 31 Jul 2025 15:18:02 +0200
Subject: [PATCH v1 1/6] Fix mixups of FooGetDatum() vs. DatumGetFoo()

Some of these were accidentally reversed, but there was no ill effect.
---
 contrib/pageinspect/btreefuncs.c        | 2 +-
 contrib/pageinspect/gistfuncs.c         | 4 ++--
 src/backend/access/common/printsimple.c | 2 +-
 src/backend/access/nbtree/nbtcompare.c  | 4 ++--
 src/backend/access/transam/xlog.c       | 6 +++---
 5 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index 294821231fc..4e2e8891cdd 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -506,7 +506,7 @@ bt_page_print_tuples(ua_page_items *uargs)
 
 	j = 0;
 	memset(nulls, 0, sizeof(nulls));
-	values[j++] = DatumGetInt16(offset);
+	values[j++] = Int16GetDatum(offset);
 	values[j++] = ItemPointerGetDatum(&itup->t_tid);
 	values[j++] = Int32GetDatum((int) IndexTupleSize(itup));
 	values[j++] = BoolGetDatum(IndexTupleHasNulls(itup));
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index 7b16e2a1ef3..1b299374890 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -174,7 +174,7 @@ gist_page_items_bytea(PG_FUNCTION_ARGS)
 
 		memset(nulls, 0, sizeof(nulls));
 
-		values[0] = DatumGetInt16(offset);
+		values[0] = Int16GetDatum(offset);
 		values[1] = ItemPointerGetDatum(&itup->t_tid);
 		values[2] = Int32GetDatum((int) IndexTupleSize(itup));
 
@@ -281,7 +281,7 @@ gist_page_items(PG_FUNCTION_ARGS)
 
 		memset(nulls, 0, sizeof(nulls));
 
-		values[0] = DatumGetInt16(offset);
+		values[0] = Int16GetDatum(offset);
 		values[1] = ItemPointerGetDatum(&itup->t_tid);
 		values[2] = Int32GetDatum((int) IndexTupleSize(itup));
 		values[3] = BoolGetDatum(ItemIdIsDead(id));
diff --git a/src/backend/access/common/printsimple.c b/src/backend/access/common/printsimple.c
index f346ab3e812..a09c8fcd332 100644
--- a/src/backend/access/common/printsimple.c
+++ b/src/backend/access/common/printsimple.c
@@ -123,7 +123,7 @@ printsimple(TupleTableSlot *slot, DestReceiver *self)
 
 			case OIDOID:
 				{
-					Oid			num = ObjectIdGetDatum(value);
+					Oid			num = DatumGetObjectId(value);
 					char		str[10];	/* 10 digits */
 					int			len;
 
diff --git a/src/backend/access/nbtree/nbtcompare.c b/src/backend/access/nbtree/nbtcompare.c
index 4da5a3c1d16..e1b52acd20d 100644
--- a/src/backend/access/nbtree/nbtcompare.c
+++ b/src/backend/access/nbtree/nbtcompare.c
@@ -555,7 +555,7 @@ btcharcmp(PG_FUNCTION_ARGS)
 static Datum
 char_decrement(Relation rel, Datum existing, bool *underflow)
 {
-	uint8		cexisting = UInt8GetDatum(existing);
+	uint8		cexisting = DatumGetUInt8(existing);
 
 	if (cexisting == 0)
 	{
@@ -571,7 +571,7 @@ char_decrement(Relation rel, Datum existing, bool *underflow)
 static Datum
 char_increment(Relation rel, Datum existing, bool *overflow)
 {
-	uint8		cexisting = UInt8GetDatum(existing);
+	uint8		cexisting = DatumGetUInt8(existing);
 
 	if (cexisting == UCHAR_MAX)
 	{
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index b0891998b24..33cb1f9ea7b 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -9000,7 +9000,7 @@ do_pg_backup_start(const char *backupidstr, bool fast, List **tablespaces,
 	 * work correctly, it is critical that sessionBackupState is only updated
 	 * after this block is over.
 	 */
-	PG_ENSURE_ERROR_CLEANUP(do_pg_abort_backup, DatumGetBool(true));
+	PG_ENSURE_ERROR_CLEANUP(do_pg_abort_backup, BoolGetDatum(true));
 	{
 		bool		gotUniqueStartpoint = false;
 		DIR		   *tblspcdir;
@@ -9239,7 +9239,7 @@ do_pg_backup_start(const char *backupidstr, bool fast, List **tablespaces,
 
 		state->starttime = (pg_time_t) time(NULL);
 	}
-	PG_END_ENSURE_ERROR_CLEANUP(do_pg_abort_backup, DatumGetBool(true));
+	PG_END_ENSURE_ERROR_CLEANUP(do_pg_abort_backup, BoolGetDatum(true));
 
 	state->started_in_recovery = backup_started_in_recovery;
 
@@ -9579,7 +9579,7 @@ register_persistent_abort_backup_handler(void)
 
 	if (already_done)
 		return;
-	before_shmem_exit(do_pg_abort_backup, DatumGetBool(false));
+	before_shmem_exit(do_pg_abort_backup, BoolGetDatum(false));
 	already_done = true;
 }
 

base-commit: 3357471cf9f5e470dfed0c7919bcf31c7efaf2b9
-- 
2.50.1

v1-0002-Remove-useless-superfluous-Datum-conversions.patchtext/plain; charset=UTF-8; name=v1-0002-Remove-useless-superfluous-Datum-conversions.patchDownload
From 7c61db51408c4f4c1527474f43f96153644016e6 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Thu, 31 Jul 2025 15:18:02 +0200
Subject: [PATCH v1 2/6] Remove useless/superfluous Datum conversions

Remove useless DatumGetFoo() and FooGetDatum() calls.  These are
places where no conversation from or to Datum was actually happening.
---
 src/backend/commands/alter.c            |  2 +-
 src/backend/executor/execExprInterp.c   |  6 +++---
 src/backend/rewrite/rewriteDefine.c     |  5 ++---
 src/backend/statistics/extended_stats.c |  2 +-
 src/backend/tsearch/ts_parse.c          |  4 ++--
 src/backend/utils/activity/pgstat.c     |  2 +-
 src/backend/utils/adt/json.c            |  2 +-
 src/backend/utils/adt/multirangetypes.c | 14 +++++++-------
 src/backend/utils/adt/rangetypes.c      | 10 ++++------
 src/backend/utils/adt/timestamp.c       |  2 +-
 src/backend/utils/adt/varlena.c         |  5 ++---
 src/backend/utils/cache/relcache.c      |  2 +-
 12 files changed, 26 insertions(+), 30 deletions(-)

diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index c801c869c1c..cb75e11fced 100644
--- a/src/backend/commands/alter.c
+++ b/src/backend/commands/alter.c
@@ -220,7 +220,7 @@ AlterObjectRename_internal(Relation rel, Oid objectId, const char *new_name)
 		Assert(!isnull);
 		ownerId = DatumGetObjectId(datum);
 
-		if (!has_privs_of_role(GetUserId(), DatumGetObjectId(ownerId)))
+		if (!has_privs_of_role(GetUserId(), ownerId))
 			aclcheck_error(ACLCHECK_NOT_OWNER, get_object_type(classId, objectId),
 						   old_name);
 
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 1a37737d4a2..a5cfe246e63 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -2815,7 +2815,7 @@ ExecJustHashVarImpl(ExprState *state, TupleTableSlot *slot, bool *isnull)
 	*isnull = false;
 
 	if (!fcinfo->args[0].isnull)
-		return DatumGetUInt32(hashop->d.hashdatum.fn_addr(fcinfo));
+		return hashop->d.hashdatum.fn_addr(fcinfo);
 	else
 		return (Datum) 0;
 }
@@ -2849,7 +2849,7 @@ ExecJustHashVarVirtImpl(ExprState *state, TupleTableSlot *slot, bool *isnull)
 	*isnull = false;
 
 	if (!fcinfo->args[0].isnull)
-		return DatumGetUInt32(hashop->d.hashdatum.fn_addr(fcinfo));
+		return hashop->d.hashdatum.fn_addr(fcinfo);
 	else
 		return (Datum) 0;
 }
@@ -2892,7 +2892,7 @@ ExecJustHashOuterVarStrict(ExprState *state, ExprContext *econtext,
 	if (!fcinfo->args[0].isnull)
 	{
 		*isnull = false;
-		return DatumGetUInt32(hashop->d.hashdatum.fn_addr(fcinfo));
+		return hashop->d.hashdatum.fn_addr(fcinfo);
 	}
 	else
 	{
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index 8aa90b0d6fb..a96fbdc1ddd 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -725,10 +725,9 @@ EnableDisableRule(Relation rel, const char *rulename,
 	/*
 	 * Change ev_enabled if it is different from the desired new state.
 	 */
-	if (DatumGetChar(ruleform->ev_enabled) !=
-		fires_when)
+	if (ruleform->ev_enabled != fires_when)
 	{
-		ruleform->ev_enabled = CharGetDatum(fires_when);
+		ruleform->ev_enabled = fires_when;
 		CatalogTupleUpdate(pg_rewrite_desc, &ruletup->t_self, ruletup);
 
 		changed = true;
diff --git a/src/backend/statistics/extended_stats.c b/src/backend/statistics/extended_stats.c
index a8b63ec0884..3e031cf831a 100644
--- a/src/backend/statistics/extended_stats.c
+++ b/src/backend/statistics/extended_stats.c
@@ -2618,7 +2618,7 @@ make_build_data(Relation rel, StatExtEntry *stat, int numrows, HeapTuple *rows,
 			}
 			else
 			{
-				result->values[idx][i] = (Datum) datum;
+				result->values[idx][i] = datum;
 				result->nulls[idx][i] = false;
 			}
 
diff --git a/src/backend/tsearch/ts_parse.c b/src/backend/tsearch/ts_parse.c
index e5da6cf17ec..cba421892bf 100644
--- a/src/backend/tsearch/ts_parse.c
+++ b/src/backend/tsearch/ts_parse.c
@@ -218,7 +218,7 @@ LexizeExec(LexizeData *ld, ParsedLex **correspondLexem)
 					 * position and go to multiword mode
 					 */
 
-					ld->curDictId = DatumGetObjectId(map->dictIds[i]);
+					ld->curDictId = map->dictIds[i];
 					ld->posDict = i + 1;
 					ld->curSub = curVal->next;
 					if (res)
@@ -275,7 +275,7 @@ LexizeExec(LexizeData *ld, ParsedLex **correspondLexem)
 				 * dictionaries ?
 				 */
 				for (i = 0; i < map->len && !dictExists; i++)
-					if (ld->curDictId == DatumGetObjectId(map->dictIds[i]))
+					if (ld->curDictId == map->dictIds[i])
 						dictExists = true;
 
 				if (!dictExists)
diff --git a/src/backend/utils/activity/pgstat.c b/src/backend/utils/activity/pgstat.c
index 6bc91ce0dad..ffb5b8cce34 100644
--- a/src/backend/utils/activity/pgstat.c
+++ b/src/backend/utils/activity/pgstat.c
@@ -821,7 +821,7 @@ pgstat_force_next_flush(void)
 static bool
 match_db_entries(PgStatShared_HashEntry *entry, Datum match_data)
 {
-	return entry->key.dboid == DatumGetObjectId(MyDatabaseId);
+	return entry->key.dboid == MyDatabaseId;
 }
 
 /*
diff --git a/src/backend/utils/adt/json.c b/src/backend/utils/adt/json.c
index 51452755f58..e9d370cb3da 100644
--- a/src/backend/utils/adt/json.c
+++ b/src/backend/utils/adt/json.c
@@ -904,7 +904,7 @@ json_unique_hash(const void *key, Size keysize)
 
 	hash ^= hash_bytes((const unsigned char *) entry->key, entry->key_len);
 
-	return DatumGetUInt32(hash);
+	return hash;
 }
 
 static int
diff --git a/src/backend/utils/adt/multirangetypes.c b/src/backend/utils/adt/multirangetypes.c
index cd84ced5b48..1c3df19cadd 100644
--- a/src/backend/utils/adt/multirangetypes.c
+++ b/src/backend/utils/adt/multirangetypes.c
@@ -394,12 +394,13 @@ multirange_send(PG_FUNCTION_ARGS)
 	for (int i = 0; i < range_count; i++)
 	{
 		Datum		range;
+		bytea	   *b;
 
 		range = RangeTypePGetDatum(ranges[i]);
-		range = PointerGetDatum(SendFunctionCall(&cache->typioproc, range));
+		b = SendFunctionCall(&cache->typioproc, range);
 
-		pq_sendint32(buf, VARSIZE(range) - VARHDRSZ);
-		pq_sendbytes(buf, VARDATA(range), VARSIZE(range) - VARHDRSZ);
+		pq_sendint32(buf, VARSIZE(b) - VARHDRSZ);
+		pq_sendbytes(buf, VARDATA(b), VARSIZE(b) - VARHDRSZ);
 	}
 
 	PG_RETURN_BYTEA_P(pq_endtypsend(buf));
@@ -2081,15 +2082,14 @@ range_overleft_multirange_internal(TypeCacheEntry *rangetyp,
 	bool		empty;
 
 	if (RangeIsEmpty(r) || MultirangeIsEmpty(mr))
-		PG_RETURN_BOOL(false);
-
+		return false;
 
 	range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
 	Assert(!empty);
 	multirange_get_bounds(rangetyp, mr, mr->rangeCount - 1,
 						  &lower2, &upper2);
 
-	PG_RETURN_BOOL(range_cmp_bounds(rangetyp, &upper1, &upper2) <= 0);
+	return (range_cmp_bounds(rangetyp, &upper1, &upper2) <= 0);
 }
 
 Datum
@@ -2166,7 +2166,7 @@ range_overright_multirange_internal(TypeCacheEntry *rangetyp,
 	bool		empty;
 
 	if (RangeIsEmpty(r) || MultirangeIsEmpty(mr))
-		PG_RETURN_BOOL(false);
+		return false;
 
 	range_deserialize(rangetyp, r, &lower1, &upper1, &empty);
 	Assert(!empty);
diff --git a/src/backend/utils/adt/rangetypes.c b/src/backend/utils/adt/rangetypes.c
index 66cc0acf4a7..32f87b47f13 100644
--- a/src/backend/utils/adt/rangetypes.c
+++ b/src/backend/utils/adt/rangetypes.c
@@ -285,8 +285,7 @@ range_send(PG_FUNCTION_ARGS)
 
 	if (RANGE_HAS_LBOUND(flags))
 	{
-		Datum		bound = PointerGetDatum(SendFunctionCall(&cache->typioproc,
-															 lower.val));
+		bytea	   *bound = SendFunctionCall(&cache->typioproc, lower.val);
 		uint32		bound_len = VARSIZE(bound) - VARHDRSZ;
 		char	   *bound_data = VARDATA(bound);
 
@@ -296,8 +295,7 @@ range_send(PG_FUNCTION_ARGS)
 
 	if (RANGE_HAS_UBOUND(flags))
 	{
-		Datum		bound = PointerGetDatum(SendFunctionCall(&cache->typioproc,
-															 upper.val));
+		bytea	   *bound = SendFunctionCall(&cache->typioproc, upper.val);
 		uint32		bound_len = VARSIZE(bound) - VARHDRSZ;
 		char	   *bound_data = VARDATA(bound);
 
@@ -1077,8 +1075,8 @@ range_union_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2,
 		return r1;
 
 	if (strict &&
-		!DatumGetBool(range_overlaps_internal(typcache, r1, r2)) &&
-		!DatumGetBool(range_adjacent_internal(typcache, r1, r2)))
+		!range_overlaps_internal(typcache, r1, r2) &&
+		!range_adjacent_internal(typcache, r1, r2))
 		ereport(ERROR,
 				(errcode(ERRCODE_DATA_EXCEPTION),
 				 errmsg("result of range union would not be contiguous")));
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 25cff56c3d0..e640b48205b 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -4954,7 +4954,7 @@ timestamptz_trunc_internal(text *units, TimestampTz timestamp, pg_tz *tzp)
 				case DTK_SECOND:
 				case DTK_MILLISEC:
 				case DTK_MICROSEC:
-					PG_RETURN_TIMESTAMPTZ(timestamp);
+					return timestamp;
 					break;
 
 				default:
diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c
index ffae8c23abf..11b442a5941 100644
--- a/src/backend/utils/adt/varlena.c
+++ b/src/backend/utils/adt/varlena.c
@@ -408,13 +408,12 @@ text_length(Datum str)
 {
 	/* fastpath when max encoding length is one */
 	if (pg_database_encoding_max_length() == 1)
-		PG_RETURN_INT32(toast_raw_datum_size(str) - VARHDRSZ);
+		return (toast_raw_datum_size(str) - VARHDRSZ);
 	else
 	{
 		text	   *t = DatumGetTextPP(str);
 
-		PG_RETURN_INT32(pg_mbstrlen_with_len(VARDATA_ANY(t),
-											 VARSIZE_ANY_EXHDR(t)));
+		return (pg_mbstrlen_with_len(VARDATA_ANY(t), VARSIZE_ANY_EXHDR(t)));
 	}
 }
 
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 559ba9cdb2c..153d2fde6fd 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -3184,7 +3184,7 @@ AssertPendingSyncs_RelationCache(void)
 		if ((LockTagType) locallock->tag.lock.locktag_type !=
 			LOCKTAG_RELATION)
 			continue;
-		relid = ObjectIdGetDatum(locallock->tag.lock.locktag_field2);
+		relid = locallock->tag.lock.locktag_field2;
 		r = RelationIdGetRelation(relid);
 		if (!RelationIsValid(r))
 			continue;
-- 
2.50.1

v1-0003-Add-missing-Datum-conversions.patchtext/plain; charset=UTF-8; name=v1-0003-Add-missing-Datum-conversions.patchDownload
From 869185199e7a7b711afb5b51834cbb0691ee8223 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Thu, 31 Jul 2025 15:18:02 +0200
Subject: [PATCH v1 3/6] Add missing Datum conversions

Add various missing conversions from and to Datum.  The previous code
mostly relied on implicit conversions or its own explicit casts
instead of using the correct DatumGet*() or *GetDatum() functions.
---
 contrib/btree_gist/btree_enum.c             |  4 ++--
 contrib/btree_gist/btree_numeric.c          |  2 +-
 contrib/btree_gist/btree_utils_num.c        | 22 ++++++++++-----------
 contrib/intarray/_int_op.c                  |  2 +-
 contrib/intarray/_int_selfuncs.c            |  2 +-
 contrib/pageinspect/heapfuncs.c             |  2 +-
 contrib/pgrowlocks/pgrowlocks.c             |  4 ++--
 contrib/seg/seg.c                           |  4 ++--
 src/backend/access/brin/brin.c              |  4 ++--
 src/backend/access/brin/brin_bloom.c        |  2 +-
 src/backend/access/brin/brin_minmax.c       | 10 +++++-----
 src/backend/access/brin/brin_minmax_multi.c |  8 ++++----
 src/backend/access/common/heaptuple.c       |  8 ++++----
 src/backend/access/common/toast_internals.c |  4 ++--
 src/backend/catalog/objectaddress.c         |  4 ++--
 src/backend/catalog/pg_proc.c               |  2 +-
 src/backend/catalog/pg_publication.c        |  2 +-
 src/backend/catalog/pg_shdepend.c           | 12 +++++------
 src/backend/commands/event_trigger.c        |  4 ++--
 src/backend/commands/subscriptioncmds.c     |  8 ++++----
 src/backend/commands/tablecmds.c            |  2 +-
 src/backend/commands/trigger.c              |  2 +-
 src/backend/commands/tsearchcmds.c          |  8 ++++----
 src/backend/commands/user.c                 |  6 +++---
 src/backend/executor/execExprInterp.c       |  2 +-
 src/backend/statistics/attribute_stats.c    |  6 +++---
 src/backend/storage/aio/aio_funcs.c         |  2 +-
 src/backend/storage/buffer/bufmgr.c         |  4 ++--
 src/backend/storage/ipc/shmem.c             |  2 +-
 src/backend/storage/lmgr/lock.c             |  4 ++--
 src/backend/utils/adt/datum.c               |  6 +++---
 src/backend/utils/adt/jsonpath_exec.c       |  2 +-
 src/backend/utils/adt/lockfuncs.c           |  8 ++++----
 src/backend/utils/adt/multirangetypes.c     | 12 +++++------
 src/backend/utils/adt/rangetypes.c          |  8 ++++----
 src/backend/utils/adt/rangetypes_spgist.c   |  2 +-
 src/backend/utils/adt/rowtypes.c            |  4 ++--
 src/backend/utils/adt/waitfuncs.c           |  2 +-
 src/backend/utils/cache/attoptcache.c       |  2 +-
 src/backend/utils/cache/lsyscache.c         |  2 +-
 src/backend/utils/cache/relcache.c          |  2 +-
 src/backend/utils/cache/syscache.c          |  6 +++---
 src/backend/utils/sort/sortsupport.c        |  2 +-
 src/backend/utils/sort/tuplesortvariants.c  |  6 +++---
 src/pl/plperl/plperl.c                      | 10 +++++-----
 src/test/regress/regress.c                  |  2 +-
 46 files changed, 112 insertions(+), 112 deletions(-)

diff --git a/contrib/btree_gist/btree_enum.c b/contrib/btree_gist/btree_enum.c
index 83c95c7bb04..c54cf3c7bae 100644
--- a/contrib/btree_gist/btree_enum.c
+++ b/contrib/btree_gist/btree_enum.c
@@ -193,8 +193,8 @@ gbt_enum_ssup_cmp(Datum x, Datum y, SortSupport ssup)
 	return DatumGetInt32(CallerFInfoFunctionCall2(enum_cmp,
 												  ssup->ssup_extra,
 												  InvalidOid,
-												  arg1->lower,
-												  arg2->lower));
+												  ObjectIdGetDatum(arg1->lower),
+												  ObjectIdGetDatum(arg2->lower)));
 }
 
 Datum
diff --git a/contrib/btree_gist/btree_numeric.c b/contrib/btree_gist/btree_numeric.c
index a39c05d9da1..052f27b0794 100644
--- a/contrib/btree_gist/btree_numeric.c
+++ b/contrib/btree_gist/btree_numeric.c
@@ -192,7 +192,7 @@ gbt_numeric_penalty(PG_FUNCTION_ARGS)
 
 		*result = 0.0;
 
-		if (DirectFunctionCall2(numeric_gt, NumericGetDatum(ds), NumericGetDatum(nul)))
+		if (DatumGetBool(DirectFunctionCall2(numeric_gt, NumericGetDatum(ds), NumericGetDatum(nul))))
 		{
 			*result += FLT_MIN;
 			os = DatumGetNumeric(DirectFunctionCall2(numeric_div,
diff --git a/contrib/btree_gist/btree_utils_num.c b/contrib/btree_gist/btree_utils_num.c
index 346ee837d75..446fa930b92 100644
--- a/contrib/btree_gist/btree_utils_num.c
+++ b/contrib/btree_gist/btree_utils_num.c
@@ -119,38 +119,38 @@ gbt_num_fetch(GISTENTRY *entry, const gbtree_ninfo *tinfo)
 	switch (tinfo->t)
 	{
 		case gbt_t_bool:
-			datum = BoolGetDatum(*(bool *) entry->key);
+			datum = BoolGetDatum(*(bool *) DatumGetPointer(entry->key));
 			break;
 		case gbt_t_int2:
-			datum = Int16GetDatum(*(int16 *) entry->key);
+			datum = Int16GetDatum(*(int16 *) DatumGetPointer(entry->key));
 			break;
 		case gbt_t_int4:
-			datum = Int32GetDatum(*(int32 *) entry->key);
+			datum = Int32GetDatum(*(int32 *) DatumGetPointer(entry->key));
 			break;
 		case gbt_t_int8:
-			datum = Int64GetDatum(*(int64 *) entry->key);
+			datum = Int64GetDatum(*(int64 *) DatumGetPointer(entry->key));
 			break;
 		case gbt_t_oid:
 		case gbt_t_enum:
-			datum = ObjectIdGetDatum(*(Oid *) entry->key);
+			datum = ObjectIdGetDatum(*(Oid *) DatumGetPointer(entry->key));
 			break;
 		case gbt_t_float4:
-			datum = Float4GetDatum(*(float4 *) entry->key);
+			datum = Float4GetDatum(*(float4 *) DatumGetPointer(entry->key));
 			break;
 		case gbt_t_float8:
-			datum = Float8GetDatum(*(float8 *) entry->key);
+			datum = Float8GetDatum(*(float8 *) DatumGetPointer(entry->key));
 			break;
 		case gbt_t_date:
-			datum = DateADTGetDatum(*(DateADT *) entry->key);
+			datum = DateADTGetDatum(*(DateADT *) DatumGetPointer(entry->key));
 			break;
 		case gbt_t_time:
-			datum = TimeADTGetDatum(*(TimeADT *) entry->key);
+			datum = TimeADTGetDatum(*(TimeADT *) DatumGetPointer(entry->key));
 			break;
 		case gbt_t_ts:
-			datum = TimestampGetDatum(*(Timestamp *) entry->key);
+			datum = TimestampGetDatum(*(Timestamp *) DatumGetPointer(entry->key));
 			break;
 		case gbt_t_cash:
-			datum = CashGetDatum(*(Cash *) entry->key);
+			datum = CashGetDatum(*(Cash *) DatumGetPointer(entry->key));
 			break;
 		default:
 			datum = entry->key;
diff --git a/contrib/intarray/_int_op.c b/contrib/intarray/_int_op.c
index ba6d0a99995..a706e353c6f 100644
--- a/contrib/intarray/_int_op.c
+++ b/contrib/intarray/_int_op.c
@@ -108,7 +108,7 @@ _int_overlap(PG_FUNCTION_ARGS)
 	CHECKARRVALID(a);
 	CHECKARRVALID(b);
 	if (ARRISEMPTY(a) || ARRISEMPTY(b))
-		return false;
+		PG_RETURN_BOOL(false);
 
 	SORT(a);
 	SORT(b);
diff --git a/contrib/intarray/_int_selfuncs.c b/contrib/intarray/_int_selfuncs.c
index 6c3b7ace146..9bf64486242 100644
--- a/contrib/intarray/_int_selfuncs.c
+++ b/contrib/intarray/_int_selfuncs.c
@@ -177,7 +177,7 @@ _int_matchsel(PG_FUNCTION_ARGS)
 	if (query->size == 0)
 	{
 		ReleaseVariableStats(vardata);
-		return (Selectivity) 0.0;
+		PG_RETURN_FLOAT8(0.0);
 	}
 
 	/*
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index 377ae30d1fa..c13f07655c4 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -256,7 +256,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 					nulls[11] = true;
 
 				if (tuphdr->t_infomask & HEAP_HASOID_OLD)
-					values[12] = HeapTupleHeaderGetOidOld(tuphdr);
+					values[12] = ObjectIdGetDatum(HeapTupleHeaderGetOidOld(tuphdr));
 				else
 					nulls[12] = true;
 
diff --git a/contrib/pgrowlocks/pgrowlocks.c b/contrib/pgrowlocks/pgrowlocks.c
index b75d80fa7a9..f88269332b6 100644
--- a/contrib/pgrowlocks/pgrowlocks.c
+++ b/contrib/pgrowlocks/pgrowlocks.c
@@ -141,8 +141,8 @@ pgrowlocks(PG_FUNCTION_ARGS)
 		 */
 		if (htsu == TM_BeingModified)
 		{
-			values[Atnum_tid] = (char *) DirectFunctionCall1(tidout,
-															 PointerGetDatum(&tuple->t_self));
+			values[Atnum_tid] = DatumGetCString(DirectFunctionCall1(tidout,
+																	PointerGetDatum(&tuple->t_self)));
 
 			values[Atnum_xmax] = palloc(NCHARS * sizeof(char));
 			snprintf(values[Atnum_xmax], NCHARS, "%u", xmax);
diff --git a/contrib/seg/seg.c b/contrib/seg/seg.c
index 151cbb954b9..b5de2a5e1be 100644
--- a/contrib/seg/seg.c
+++ b/contrib/seg/seg.c
@@ -417,7 +417,7 @@ gseg_same(PG_FUNCTION_ARGS)
 {
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
 
-	if (DirectFunctionCall2(seg_same, PG_GETARG_DATUM(0), PG_GETARG_DATUM(1)))
+	if (DatumGetBool(DirectFunctionCall2(seg_same, PG_GETARG_DATUM(0), PG_GETARG_DATUM(1))))
 		*result = true;
 	else
 		*result = false;
@@ -470,7 +470,7 @@ gseg_leaf_consistent(Datum key, Datum query, StrategyNumber strategy)
 			retval = DirectFunctionCall2(seg_contained, key, query);
 			break;
 		default:
-			retval = false;
+			retval = BoolGetDatum(false);
 	}
 
 	PG_RETURN_DATUM(retval);
diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c
index 4204088fa0d..7ff7467e462 100644
--- a/src/backend/access/brin/brin.c
+++ b/src/backend/access/brin/brin.c
@@ -1608,7 +1608,7 @@ brin_build_desc(Relation rel)
 		opcInfoFn = index_getprocinfo(rel, keyno + 1, BRIN_PROCNUM_OPCINFO);
 
 		opcinfo[keyno] = (BrinOpcInfo *)
-			DatumGetPointer(FunctionCall1(opcInfoFn, attr->atttypid));
+			DatumGetPointer(FunctionCall1(opcInfoFn, ObjectIdGetDatum(attr->atttypid)));
 		totalstored += opcinfo[keyno]->oi_nstored;
 	}
 
@@ -2262,7 +2262,7 @@ add_values_to_range(Relation idxRel, BrinDesc *bdesc, BrinMemTuple *dtup,
 								   PointerGetDatum(bdesc),
 								   PointerGetDatum(bval),
 								   values[keyno],
-								   nulls[keyno]);
+								   BoolGetDatum(nulls[keyno]));
 		/* if that returned true, we need to insert the updated tuple */
 		modified |= DatumGetBool(result);
 
diff --git a/src/backend/access/brin/brin_bloom.c b/src/backend/access/brin/brin_bloom.c
index 82b425ce37d..7c3f7d454fc 100644
--- a/src/backend/access/brin/brin_bloom.c
+++ b/src/backend/access/brin/brin_bloom.c
@@ -540,7 +540,7 @@ brin_bloom_add_value(PG_FUNCTION_ARGS)
 	BrinDesc   *bdesc = (BrinDesc *) PG_GETARG_POINTER(0);
 	BrinValues *column = (BrinValues *) PG_GETARG_POINTER(1);
 	Datum		newval = PG_GETARG_DATUM(2);
-	bool		isnull PG_USED_FOR_ASSERTS_ONLY = PG_GETARG_DATUM(3);
+	bool		isnull PG_USED_FOR_ASSERTS_ONLY = PG_GETARG_BOOL(3);
 	BloomOptions *opts = (BloomOptions *) PG_GET_OPCLASS_OPTIONS();
 	Oid			colloid = PG_GET_COLLATION();
 	FmgrInfo   *hashFn;
diff --git a/src/backend/access/brin/brin_minmax.c b/src/backend/access/brin/brin_minmax.c
index d21ab3a668c..79c5a0aa185 100644
--- a/src/backend/access/brin/brin_minmax.c
+++ b/src/backend/access/brin/brin_minmax.c
@@ -66,7 +66,7 @@ brin_minmax_add_value(PG_FUNCTION_ARGS)
 	BrinDesc   *bdesc = (BrinDesc *) PG_GETARG_POINTER(0);
 	BrinValues *column = (BrinValues *) PG_GETARG_POINTER(1);
 	Datum		newval = PG_GETARG_DATUM(2);
-	bool		isnull PG_USED_FOR_ASSERTS_ONLY = PG_GETARG_DATUM(3);
+	bool		isnull PG_USED_FOR_ASSERTS_ONLY = PG_GETARG_BOOL(3);
 	Oid			colloid = PG_GET_COLLATION();
 	FmgrInfo   *cmpFn;
 	Datum		compar;
@@ -225,8 +225,8 @@ brin_minmax_union(PG_FUNCTION_ARGS)
 	/* Adjust minimum, if B's min is less than A's min */
 	finfo = minmax_get_strategy_procinfo(bdesc, attno, attr->atttypid,
 										 BTLessStrategyNumber);
-	needsadj = FunctionCall2Coll(finfo, colloid, col_b->bv_values[0],
-								 col_a->bv_values[0]);
+	needsadj = DatumGetBool(FunctionCall2Coll(finfo, colloid, col_b->bv_values[0],
+											  col_a->bv_values[0]));
 	if (needsadj)
 	{
 		if (!attr->attbyval)
@@ -238,8 +238,8 @@ brin_minmax_union(PG_FUNCTION_ARGS)
 	/* Adjust maximum, if B's max is greater than A's max */
 	finfo = minmax_get_strategy_procinfo(bdesc, attno, attr->atttypid,
 										 BTGreaterStrategyNumber);
-	needsadj = FunctionCall2Coll(finfo, colloid, col_b->bv_values[1],
-								 col_a->bv_values[1]);
+	needsadj = DatumGetBool(FunctionCall2Coll(finfo, colloid, col_b->bv_values[1],
+											  col_a->bv_values[1]));
 	if (needsadj)
 	{
 		if (!attr->attbyval)
diff --git a/src/backend/access/brin/brin_minmax_multi.c b/src/backend/access/brin/brin_minmax_multi.c
index 0d1507a2a36..478e58b5bf2 100644
--- a/src/backend/access/brin/brin_minmax_multi.c
+++ b/src/backend/access/brin/brin_minmax_multi.c
@@ -1992,8 +1992,8 @@ brin_minmax_multi_distance_tid(PG_FUNCTION_ARGS)
 	double		da1,
 				da2;
 
-	ItemPointer pa1 = (ItemPointer) PG_GETARG_DATUM(0);
-	ItemPointer pa2 = (ItemPointer) PG_GETARG_DATUM(1);
+	ItemPointer pa1 = (ItemPointer) PG_GETARG_POINTER(0);
+	ItemPointer pa2 = (ItemPointer) PG_GETARG_POINTER(1);
 
 	/*
 	 * We know the values are range boundaries, but the range may be collapsed
@@ -2032,7 +2032,7 @@ brin_minmax_multi_distance_numeric(PG_FUNCTION_ARGS)
 
 	d = DirectFunctionCall2(numeric_sub, a2, a1);	/* a2 - a1 */
 
-	PG_RETURN_FLOAT8(DirectFunctionCall1(numeric_float8, d));
+	PG_RETURN_FLOAT8(DatumGetFloat8(DirectFunctionCall1(numeric_float8, d)));
 }
 
 /*
@@ -2414,7 +2414,7 @@ brin_minmax_multi_add_value(PG_FUNCTION_ARGS)
 	BrinDesc   *bdesc = (BrinDesc *) PG_GETARG_POINTER(0);
 	BrinValues *column = (BrinValues *) PG_GETARG_POINTER(1);
 	Datum		newval = PG_GETARG_DATUM(2);
-	bool		isnull PG_USED_FOR_ASSERTS_ONLY = PG_GETARG_DATUM(3);
+	bool		isnull PG_USED_FOR_ASSERTS_ONLY = PG_GETARG_BOOL(3);
 	MinMaxMultiOptions *opts = (MinMaxMultiOptions *) PG_GET_OPCLASS_OPTIONS();
 	Oid			colloid = PG_GET_COLLATION();
 	bool		modified = false;
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 969d1028cae..09823a16358 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -105,7 +105,7 @@ missing_hash(const void *key, Size keysize)
 {
 	const missing_cache_key *entry = (missing_cache_key *) key;
 
-	return hash_bytes((const unsigned char *) entry->value, entry->len);
+	return hash_bytes((const unsigned char *) DatumGetPointer(entry->value), entry->len);
 }
 
 static int
@@ -901,9 +901,9 @@ expand_tuple(HeapTuple *targetHeapTuple,
 												  att->attlen,
 												  attrmiss[attnum].am_value);
 
-				targetDataLen = att_addlength_pointer(targetDataLen,
-													  att->attlen,
-													  attrmiss[attnum].am_value);
+				targetDataLen = att_addlength_datum(targetDataLen,
+													att->attlen,
+													attrmiss[attnum].am_value);
 			}
 			else
 			{
diff --git a/src/backend/access/common/toast_internals.c b/src/backend/access/common/toast_internals.c
index 7d8be8346ce..8d86c3b6ea6 100644
--- a/src/backend/access/common/toast_internals.c
+++ b/src/backend/access/common/toast_internals.c
@@ -64,11 +64,11 @@ toast_compress_datum(Datum value, char cmethod)
 	switch (cmethod)
 	{
 		case TOAST_PGLZ_COMPRESSION:
-			tmp = pglz_compress_datum((const struct varlena *) value);
+			tmp = pglz_compress_datum((const struct varlena *) DatumGetPointer(value));
 			cmid = TOAST_PGLZ_COMPRESSION_ID;
 			break;
 		case TOAST_LZ4_COMPRESSION:
-			tmp = lz4_compress_datum((const struct varlena *) value);
+			tmp = lz4_compress_datum((const struct varlena *) DatumGetPointer(value));
 			cmid = TOAST_LZ4_COMPRESSION_ID;
 			break;
 		default:
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index b63fd57dc04..0102c9984e7 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -4283,8 +4283,8 @@ pg_identify_object(PG_FUNCTION_ARGS)
 			nspAttnum = get_object_attnum_namespace(address.classId);
 			if (nspAttnum != InvalidAttrNumber)
 			{
-				schema_oid = heap_getattr(objtup, nspAttnum,
-										  RelationGetDescr(catalog), &isnull);
+				schema_oid = DatumGetObjectId(heap_getattr(objtup, nspAttnum,
+														   RelationGetDescr(catalog), &isnull));
 				if (isnull)
 					elog(ERROR, "invalid null namespace in object %u/%u/%d",
 						 address.classId, address.objectId, address.objectSubId);
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 5fdcf24d5f8..75b17fed15e 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -1212,6 +1212,6 @@ oid_array_to_list(Datum datum)
 
 	deconstruct_array_builtin(array, OIDOID, &values, NULL, &nelems);
 	for (i = 0; i < nelems; i++)
-		result = lappend_oid(result, values[i]);
+		result = lappend_oid(result, DatumGetObjectId(values[i]));
 	return result;
 }
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c
index d6f94db5d99..b911efcf9cb 100644
--- a/src/backend/catalog/pg_publication.c
+++ b/src/backend/catalog/pg_publication.c
@@ -1001,7 +1001,7 @@ GetSchemaPublicationRelations(Oid schemaid, PublicationPartOpt pub_partopt)
 	ScanKeyInit(&key[0],
 				Anum_pg_class_relnamespace,
 				BTEqualStrategyNumber, F_OIDEQ,
-				schemaid);
+				ObjectIdGetDatum(schemaid));
 
 	/* get all the relations present in the specified schema */
 	scan = table_beginscan_catalog(classRel, 1, key);
diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c
index 536191284e8..32e544da28a 100644
--- a/src/backend/catalog/pg_shdepend.c
+++ b/src/backend/catalog/pg_shdepend.c
@@ -956,12 +956,12 @@ copyTemplateDependencies(Oid templateDbId, Oid newDbId)
 		shdep = (Form_pg_shdepend) GETSTRUCT(tup);
 
 		slot[slot_stored_count]->tts_values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(newDbId);
-		slot[slot_stored_count]->tts_values[Anum_pg_shdepend_classid - 1] = shdep->classid;
-		slot[slot_stored_count]->tts_values[Anum_pg_shdepend_objid - 1] = shdep->objid;
-		slot[slot_stored_count]->tts_values[Anum_pg_shdepend_objsubid - 1] = shdep->objsubid;
-		slot[slot_stored_count]->tts_values[Anum_pg_shdepend_refclassid - 1] = shdep->refclassid;
-		slot[slot_stored_count]->tts_values[Anum_pg_shdepend_refobjid - 1] = shdep->refobjid;
-		slot[slot_stored_count]->tts_values[Anum_pg_shdepend_deptype - 1] = shdep->deptype;
+		slot[slot_stored_count]->tts_values[Anum_pg_shdepend_classid - 1] = ObjectIdGetDatum(shdep->classid);
+		slot[slot_stored_count]->tts_values[Anum_pg_shdepend_objid - 1] = ObjectIdGetDatum(shdep->objid);
+		slot[slot_stored_count]->tts_values[Anum_pg_shdepend_objsubid - 1] = Int32GetDatum(shdep->objsubid);
+		slot[slot_stored_count]->tts_values[Anum_pg_shdepend_refclassid - 1] = ObjectIdGetDatum(shdep->refclassid);
+		slot[slot_stored_count]->tts_values[Anum_pg_shdepend_refobjid - 1] = ObjectIdGetDatum(shdep->refobjid);
+		slot[slot_stored_count]->tts_values[Anum_pg_shdepend_deptype - 1] = CharGetDatum(shdep->deptype);
 
 		ExecStoreVirtualTuple(slot[slot_stored_count]);
 		slot_stored_count++;
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index edc2c988e29..631fb0525f1 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -2021,8 +2021,8 @@ pg_event_trigger_ddl_commands(PG_FUNCTION_ARGS)
 								elog(ERROR, "cache lookup failed for object %u/%u",
 									 addr.classId, addr.objectId);
 							schema_oid =
-								heap_getattr(objtup, nspAttnum,
-											 RelationGetDescr(catalog), &isnull);
+								DatumGetObjectId(heap_getattr(objtup, nspAttnum,
+															  RelationGetDescr(catalog), &isnull));
 							if (isnull)
 								elog(ERROR,
 									 "invalid null namespace in object %u/%u/%d",
diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c
index cd6c3684482..faa3650d287 100644
--- a/src/backend/commands/subscriptioncmds.c
+++ b/src/backend/commands/subscriptioncmds.c
@@ -638,7 +638,7 @@ CreateSubscription(ParseState *pstate, CreateSubscriptionStmt *stmt,
 
 	/* Check if name is used */
 	subid = GetSysCacheOid2(SUBSCRIPTIONNAME, Anum_pg_subscription_oid,
-							MyDatabaseId, CStringGetDatum(stmt->subname));
+							ObjectIdGetDatum(MyDatabaseId), CStringGetDatum(stmt->subname));
 	if (OidIsValid(subid))
 	{
 		ereport(ERROR,
@@ -1185,7 +1185,7 @@ AlterSubscription(ParseState *pstate, AlterSubscriptionStmt *stmt,
 	rel = table_open(SubscriptionRelationId, RowExclusiveLock);
 
 	/* Fetch the existing tuple. */
-	tup = SearchSysCacheCopy2(SUBSCRIPTIONNAME, MyDatabaseId,
+	tup = SearchSysCacheCopy2(SUBSCRIPTIONNAME, ObjectIdGetDatum(MyDatabaseId),
 							  CStringGetDatum(stmt->subname));
 
 	if (!HeapTupleIsValid(tup))
@@ -1808,7 +1808,7 @@ DropSubscription(DropSubscriptionStmt *stmt, bool isTopLevel)
 	 */
 	rel = table_open(SubscriptionRelationId, AccessExclusiveLock);
 
-	tup = SearchSysCache2(SUBSCRIPTIONNAME, MyDatabaseId,
+	tup = SearchSysCache2(SUBSCRIPTIONNAME, ObjectIdGetDatum(MyDatabaseId),
 						  CStringGetDatum(stmt->subname));
 
 	if (!HeapTupleIsValid(tup))
@@ -2193,7 +2193,7 @@ AlterSubscriptionOwner(const char *name, Oid newOwnerId)
 
 	rel = table_open(SubscriptionRelationId, RowExclusiveLock);
 
-	tup = SearchSysCacheCopy2(SUBSCRIPTIONNAME, MyDatabaseId,
+	tup = SearchSysCacheCopy2(SUBSCRIPTIONNAME, ObjectIdGetDatum(MyDatabaseId),
 							  CStringGetDatum(name));
 
 	if (!HeapTupleIsValid(tup))
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index cb811520c29..c6dd2e020da 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -8985,7 +8985,7 @@ ATExecSetStatistics(Relation rel, const char *colName, int16 colNum, Node *newVa
 	memset(repl_null, false, sizeof(repl_null));
 	memset(repl_repl, false, sizeof(repl_repl));
 	if (!newtarget_default)
-		repl_val[Anum_pg_attribute_attstattarget - 1] = newtarget;
+		repl_val[Anum_pg_attribute_attstattarget - 1] = Int16GetDatum(newtarget);
 	else
 		repl_null[Anum_pg_attribute_attstattarget - 1] = true;
 	repl_repl[Anum_pg_attribute_attstattarget - 1] = true;
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 7dc121f73f1..c909d1b8bd8 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -872,7 +872,7 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
 															 CStringGetDatum(trigname));
 	values[Anum_pg_trigger_tgfoid - 1] = ObjectIdGetDatum(funcoid);
 	values[Anum_pg_trigger_tgtype - 1] = Int16GetDatum(tgtype);
-	values[Anum_pg_trigger_tgenabled - 1] = trigger_fires_when;
+	values[Anum_pg_trigger_tgenabled - 1] = CharGetDatum(trigger_fires_when);
 	values[Anum_pg_trigger_tgisinternal - 1] = BoolGetDatum(isInternal);
 	values[Anum_pg_trigger_tgconstrrelid - 1] = ObjectIdGetDatum(constrrelid);
 	values[Anum_pg_trigger_tgconstrindid - 1] = ObjectIdGetDatum(indexOid);
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index ab16d42ad56..dc7df736fb8 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -1058,10 +1058,10 @@ DefineTSConfiguration(List *names, List *parameters, ObjectAddress *copied)
 			memset(slot[slot_stored_count]->tts_isnull, false,
 				   slot[slot_stored_count]->tts_tupleDescriptor->natts * sizeof(bool));
 
-			slot[slot_stored_count]->tts_values[Anum_pg_ts_config_map_mapcfg - 1] = cfgOid;
-			slot[slot_stored_count]->tts_values[Anum_pg_ts_config_map_maptokentype - 1] = cfgmap->maptokentype;
-			slot[slot_stored_count]->tts_values[Anum_pg_ts_config_map_mapseqno - 1] = cfgmap->mapseqno;
-			slot[slot_stored_count]->tts_values[Anum_pg_ts_config_map_mapdict - 1] = cfgmap->mapdict;
+			slot[slot_stored_count]->tts_values[Anum_pg_ts_config_map_mapcfg - 1] = ObjectIdGetDatum(cfgOid);
+			slot[slot_stored_count]->tts_values[Anum_pg_ts_config_map_maptokentype - 1] = Int32GetDatum(cfgmap->maptokentype);
+			slot[slot_stored_count]->tts_values[Anum_pg_ts_config_map_mapseqno - 1] = Int32GetDatum(cfgmap->mapseqno);
+			slot[slot_stored_count]->tts_values[Anum_pg_ts_config_map_mapdict - 1] = ObjectIdGetDatum(cfgmap->mapdict);
 
 			ExecStoreVirtualTuple(slot[slot_stored_count]);
 			slot_stored_count++;
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index 0d638e29d00..1e3d4ab0e20 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -1924,7 +1924,7 @@ AddRoleMems(Oid currentUserId, const char *rolename, Oid roleid,
 			 */
 			if ((popt->specified & GRANT_ROLE_SPECIFIED_INHERIT) != 0)
 				new_record[Anum_pg_auth_members_inherit_option - 1] =
-					popt->inherit;
+					BoolGetDatum(popt->inherit);
 			else
 			{
 				HeapTuple	mrtup;
@@ -1935,14 +1935,14 @@ AddRoleMems(Oid currentUserId, const char *rolename, Oid roleid,
 					elog(ERROR, "cache lookup failed for role %u", memberid);
 				mrform = (Form_pg_authid) GETSTRUCT(mrtup);
 				new_record[Anum_pg_auth_members_inherit_option - 1] =
-					mrform->rolinherit;
+					BoolGetDatum(mrform->rolinherit);
 				ReleaseSysCache(mrtup);
 			}
 
 			/* get an OID for the new row and insert it */
 			objectId = GetNewOidWithIndex(pg_authmem_rel, AuthMemOidIndexId,
 										  Anum_pg_auth_members_oid);
-			new_record[Anum_pg_auth_members_oid - 1] = objectId;
+			new_record[Anum_pg_auth_members_oid - 1] = ObjectIdGetDatum(objectId);
 			tuple = heap_form_tuple(pg_authmem_dsc,
 									new_record, new_record_nulls);
 			CatalogTupleInsert(pg_authmem_rel, tuple);
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index a5cfe246e63..0e1a74976f7 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -4393,7 +4393,7 @@ ExecEvalHashedScalarArrayOp(ExprState *state, ExprEvalStep *op, ExprContext *eco
 			 * is the equality function and we need not-equals.
 			 */
 			if (!inclause)
-				result = !result;
+				result = BoolGetDatum(!DatumGetBool(result));
 		}
 	}
 
diff --git a/src/backend/statistics/attribute_stats.c b/src/backend/statistics/attribute_stats.c
index ab198076401..e8241926d2c 100644
--- a/src/backend/statistics/attribute_stats.c
+++ b/src/backend/statistics/attribute_stats.c
@@ -339,7 +339,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo)
 
 	starel = table_open(StatisticRelationId, RowExclusiveLock);
 
-	statup = SearchSysCache3(STATRELATTINH, reloid, attnum, inherited);
+	statup = SearchSysCache3(STATRELATTINH, ObjectIdGetDatum(reloid), Int16GetDatum(attnum), BoolGetDatum(inherited));
 
 	/* initialize from existing tuple if exists */
 	if (HeapTupleIsValid(statup))
@@ -895,9 +895,9 @@ init_empty_stats_tuple(Oid reloid, int16 attnum, bool inherited,
 	{
 		values[Anum_pg_statistic_stakind1 + slotnum - 1] = (Datum) 0;
 		nulls[Anum_pg_statistic_stakind1 + slotnum - 1] = false;
-		values[Anum_pg_statistic_staop1 + slotnum - 1] = InvalidOid;
+		values[Anum_pg_statistic_staop1 + slotnum - 1] = ObjectIdGetDatum(InvalidOid);
 		nulls[Anum_pg_statistic_staop1 + slotnum - 1] = false;
-		values[Anum_pg_statistic_stacoll1 + slotnum - 1] = InvalidOid;
+		values[Anum_pg_statistic_stacoll1 + slotnum - 1] = ObjectIdGetDatum(InvalidOid);
 		nulls[Anum_pg_statistic_stacoll1 + slotnum - 1] = false;
 	}
 }
diff --git a/src/backend/storage/aio/aio_funcs.c b/src/backend/storage/aio/aio_funcs.c
index 584e683371a..b25f9204041 100644
--- a/src/backend/storage/aio/aio_funcs.c
+++ b/src/backend/storage/aio/aio_funcs.c
@@ -152,7 +152,7 @@ pg_get_aios(PG_FUNCTION_ARGS)
 			nulls[0] = false;
 
 		/* column: IO's id */
-		values[1] = ioh_id;
+		values[1] = UInt32GetDatum(ioh_id); // XXX
 
 		/* column: IO's generation */
 		values[2] = Int64GetDatum(start_generation);
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 67431208e7f..c50b4a2cd2f 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -6370,8 +6370,8 @@ ckpt_buforder_comparator(const CkptSortItem *a, const CkptSortItem *b)
 static int
 ts_ckpt_progress_comparator(Datum a, Datum b, void *arg)
 {
-	CkptTsStatus *sa = (CkptTsStatus *) a;
-	CkptTsStatus *sb = (CkptTsStatus *) b;
+	CkptTsStatus *sa = (CkptTsStatus *) DatumGetPointer(a);
+	CkptTsStatus *sb = (CkptTsStatus *) DatumGetPointer(b);
 
 	/* we want a min-heap, so return 1 for the a < b */
 	if (sa->progress < sb->progress)
diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c
index ca3656fc76f..d12a3ca0684 100644
--- a/src/backend/storage/ipc/shmem.c
+++ b/src/backend/storage/ipc/shmem.c
@@ -714,7 +714,7 @@ pg_get_shmem_allocations_numa(PG_FUNCTION_ARGS)
 		for (i = 0; i <= max_nodes; i++)
 		{
 			values[0] = CStringGetTextDatum(ent->key);
-			values[1] = i;
+			values[1] = Int32GetDatum(i);
 			values[2] = Int64GetDatum(nodes[i] * os_page_size);
 
 			tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 62f3471448e..f8c88147160 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -589,7 +589,7 @@ proclock_hash(const void *key, Size keysize)
 	 * intermediate variable to suppress cast-pointer-to-int warnings.
 	 */
 	procptr = PointerGetDatum(proclocktag->myProc);
-	lockhash ^= ((uint32) procptr) << LOG2_NUM_LOCK_PARTITIONS;
+	lockhash ^= DatumGetUInt32(procptr) << LOG2_NUM_LOCK_PARTITIONS;
 
 	return lockhash;
 }
@@ -610,7 +610,7 @@ ProcLockHashCode(const PROCLOCKTAG *proclocktag, uint32 hashcode)
 	 * This must match proclock_hash()!
 	 */
 	procptr = PointerGetDatum(proclocktag->myProc);
-	lockhash ^= ((uint32) procptr) << LOG2_NUM_LOCK_PARTITIONS;
+	lockhash ^= DatumGetUInt32(procptr) << LOG2_NUM_LOCK_PARTITIONS;
 
 	return lockhash;
 }
diff --git a/src/backend/utils/adt/datum.c b/src/backend/utils/adt/datum.c
index fcd5b1653dd..614644a4e2a 100644
--- a/src/backend/utils/adt/datum.c
+++ b/src/backend/utils/adt/datum.c
@@ -299,9 +299,9 @@ datum_image_eq(Datum value1, Datum value2, bool typByVal, int typLen)
 							 len1 - VARHDRSZ) == 0);
 
 			/* Only free memory if it's a copy made here. */
-			if ((Pointer) arg1val != (Pointer) value1)
+			if ((Pointer) arg1val != DatumGetPointer(value1))
 				pfree(arg1val);
-			if ((Pointer) arg2val != (Pointer) value2)
+			if ((Pointer) arg2val != DatumGetPointer(value2))
 				pfree(arg2val);
 		}
 	}
@@ -355,7 +355,7 @@ datum_image_hash(Datum value, bool typByVal, int typLen)
 		result = hash_bytes((unsigned char *) VARDATA_ANY(val), len - VARHDRSZ);
 
 		/* Only free memory if it's a copy made here. */
-		if ((Pointer) val != (Pointer) value)
+		if ((Pointer) val != DatumGetPointer(value))
 			pfree(val);
 	}
 	else if (typLen == -2)
diff --git a/src/backend/utils/adt/jsonpath_exec.c b/src/backend/utils/adt/jsonpath_exec.c
index dbab24737ef..21c2cf3c71d 100644
--- a/src/backend/utils/adt/jsonpath_exec.c
+++ b/src/backend/utils/adt/jsonpath_exec.c
@@ -1517,7 +1517,7 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
 					/* Convert numstr to Numeric with typmod */
 					Assert(numstr != NULL);
 					noerr = DirectInputFunctionCallSafe(numeric_in, numstr,
-														InvalidOid, dtypmod,
+														InvalidOid, DatumGetInt32(dtypmod),
 														(Node *) &escontext,
 														&numdatum);
 
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 00e67fb46d0..df938812dd3 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -398,15 +398,15 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		values[0] = CStringGetTextDatum(PredicateLockTagTypeNames[lockType]);
 
 		/* lock target */
-		values[1] = GET_PREDICATELOCKTARGETTAG_DB(*predTag);
-		values[2] = GET_PREDICATELOCKTARGETTAG_RELATION(*predTag);
+		values[1] = ObjectIdGetDatum(GET_PREDICATELOCKTARGETTAG_DB(*predTag));
+		values[2] = ObjectIdGetDatum(GET_PREDICATELOCKTARGETTAG_RELATION(*predTag));
 		if (lockType == PREDLOCKTAG_TUPLE)
-			values[4] = GET_PREDICATELOCKTARGETTAG_OFFSET(*predTag);
+			values[4] = UInt16GetDatum(GET_PREDICATELOCKTARGETTAG_OFFSET(*predTag));
 		else
 			nulls[4] = true;
 		if ((lockType == PREDLOCKTAG_TUPLE) ||
 			(lockType == PREDLOCKTAG_PAGE))
-			values[3] = GET_PREDICATELOCKTARGETTAG_PAGE(*predTag);
+			values[3] = UInt32GetDatum(GET_PREDICATELOCKTARGETTAG_PAGE(*predTag));
 		else
 			nulls[3] = true;
 
diff --git a/src/backend/utils/adt/multirangetypes.c b/src/backend/utils/adt/multirangetypes.c
index 1c3df19cadd..4c3db172e76 100644
--- a/src/backend/utils/adt/multirangetypes.c
+++ b/src/backend/utils/adt/multirangetypes.c
@@ -2523,7 +2523,7 @@ multirange_adjacent_range(PG_FUNCTION_ARGS)
 	TypeCacheEntry *typcache;
 
 	if (RangeIsEmpty(r) || MultirangeIsEmpty(mr))
-		return false;
+		PG_RETURN_BOOL(false);
 
 	typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
 
@@ -2544,7 +2544,7 @@ multirange_adjacent_multirange(PG_FUNCTION_ARGS)
 				upper2;
 
 	if (MultirangeIsEmpty(mr1) || MultirangeIsEmpty(mr2))
-		return false;
+		PG_RETURN_BOOL(false);
 
 	typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr1));
 
@@ -2639,7 +2639,7 @@ multirange_cmp(PG_FUNCTION_ARGS)
 Datum
 multirange_lt(PG_FUNCTION_ARGS)
 {
-	int			cmp = multirange_cmp(fcinfo);
+	int			cmp = DatumGetInt32(multirange_cmp(fcinfo));
 
 	PG_RETURN_BOOL(cmp < 0);
 }
@@ -2647,7 +2647,7 @@ multirange_lt(PG_FUNCTION_ARGS)
 Datum
 multirange_le(PG_FUNCTION_ARGS)
 {
-	int			cmp = multirange_cmp(fcinfo);
+	int			cmp = DatumGetInt32(multirange_cmp(fcinfo));
 
 	PG_RETURN_BOOL(cmp <= 0);
 }
@@ -2655,7 +2655,7 @@ multirange_le(PG_FUNCTION_ARGS)
 Datum
 multirange_ge(PG_FUNCTION_ARGS)
 {
-	int			cmp = multirange_cmp(fcinfo);
+	int			cmp = DatumGetInt32(multirange_cmp(fcinfo));
 
 	PG_RETURN_BOOL(cmp >= 0);
 }
@@ -2663,7 +2663,7 @@ multirange_ge(PG_FUNCTION_ARGS)
 Datum
 multirange_gt(PG_FUNCTION_ARGS)
 {
-	int			cmp = multirange_cmp(fcinfo);
+	int			cmp = DatumGetInt32(multirange_cmp(fcinfo));
 
 	PG_RETURN_BOOL(cmp > 0);
 }
diff --git a/src/backend/utils/adt/rangetypes.c b/src/backend/utils/adt/rangetypes.c
index 32f87b47f13..f26dbfa4c97 100644
--- a/src/backend/utils/adt/rangetypes.c
+++ b/src/backend/utils/adt/rangetypes.c
@@ -1356,7 +1356,7 @@ range_fast_cmp(Datum a, Datum b, SortSupport ssup)
 Datum
 range_lt(PG_FUNCTION_ARGS)
 {
-	int			cmp = range_cmp(fcinfo);
+	int			cmp = DatumGetInt32(range_cmp(fcinfo));
 
 	PG_RETURN_BOOL(cmp < 0);
 }
@@ -1364,7 +1364,7 @@ range_lt(PG_FUNCTION_ARGS)
 Datum
 range_le(PG_FUNCTION_ARGS)
 {
-	int			cmp = range_cmp(fcinfo);
+	int			cmp = DatumGetInt32(range_cmp(fcinfo));
 
 	PG_RETURN_BOOL(cmp <= 0);
 }
@@ -1372,7 +1372,7 @@ range_le(PG_FUNCTION_ARGS)
 Datum
 range_ge(PG_FUNCTION_ARGS)
 {
-	int			cmp = range_cmp(fcinfo);
+	int			cmp = DatumGetInt32(range_cmp(fcinfo));
 
 	PG_RETURN_BOOL(cmp >= 0);
 }
@@ -1380,7 +1380,7 @@ range_ge(PG_FUNCTION_ARGS)
 Datum
 range_gt(PG_FUNCTION_ARGS)
 {
-	int			cmp = range_cmp(fcinfo);
+	int			cmp = DatumGetInt32(range_cmp(fcinfo));
 
 	PG_RETURN_BOOL(cmp > 0);
 }
diff --git a/src/backend/utils/adt/rangetypes_spgist.c b/src/backend/utils/adt/rangetypes_spgist.c
index 9b6d7061a18..be519654880 100644
--- a/src/backend/utils/adt/rangetypes_spgist.c
+++ b/src/backend/utils/adt/rangetypes_spgist.c
@@ -757,7 +757,7 @@ spg_range_quad_inner_consistent(PG_FUNCTION_ARGS)
 				 * because it's range
 				 */
 				previousCentroid = datumCopy(in->prefixDatum, false, -1);
-				out->traversalValues[out->nNodes] = (void *) previousCentroid;
+				out->traversalValues[out->nNodes] = DatumGetPointer(previousCentroid);
 			}
 			out->nodeNumbers[out->nNodes] = i - 1;
 			out->nNodes++;
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index fe5edc0027d..9e5449f17d7 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -1529,9 +1529,9 @@ record_image_cmp(FunctionCallInfo fcinfo)
 				if ((cmpresult == 0) && (len1 != len2))
 					cmpresult = (len1 < len2) ? -1 : 1;
 
-				if ((Pointer) arg1val != (Pointer) values1[i1])
+				if ((Pointer) arg1val != DatumGetPointer(values1[i1]))
 					pfree(arg1val);
-				if ((Pointer) arg2val != (Pointer) values2[i2])
+				if ((Pointer) arg2val != DatumGetPointer(values2[i2]))
 					pfree(arg2val);
 			}
 			else
diff --git a/src/backend/utils/adt/waitfuncs.c b/src/backend/utils/adt/waitfuncs.c
index ddd0a57c0c5..f01cad72a0f 100644
--- a/src/backend/utils/adt/waitfuncs.c
+++ b/src/backend/utils/adt/waitfuncs.c
@@ -73,7 +73,7 @@ pg_isolation_test_session_is_blocked(PG_FUNCTION_ARGS)
 	 * acquire heavyweight locks.
 	 */
 	blocking_pids_a =
-		DatumGetArrayTypeP(DirectFunctionCall1(pg_blocking_pids, blocked_pid));
+		DatumGetArrayTypeP(DirectFunctionCall1(pg_blocking_pids, Int32GetDatum(blocked_pid)));
 
 	Assert(ARR_ELEMTYPE(blocking_pids_a) == INT4OID);
 	Assert(!array_contains_nulls(blocking_pids_a));
diff --git a/src/backend/utils/cache/attoptcache.c b/src/backend/utils/cache/attoptcache.c
index 5c8360c08b5..45d1e2be007 100644
--- a/src/backend/utils/cache/attoptcache.c
+++ b/src/backend/utils/cache/attoptcache.c
@@ -86,7 +86,7 @@ relatt_cache_syshash(const void *key, Size keysize)
 	const AttoptCacheKey *ckey = key;
 
 	Assert(keysize == sizeof(*ckey));
-	return GetSysCacheHashValue2(ATTNUM, ckey->attrelid, ckey->attnum);
+	return GetSysCacheHashValue2(ATTNUM, ObjectIdGetDatum(ckey->attrelid), Int32GetDatum(ckey->attnum));
 }
 
 /*
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index c460a72b75d..032bb6222c4 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -3817,7 +3817,7 @@ get_subscription_oid(const char *subname, bool missing_ok)
 	Oid			oid;
 
 	oid = GetSysCacheOid2(SUBSCRIPTIONNAME, Anum_pg_subscription_oid,
-						  MyDatabaseId, CStringGetDatum(subname));
+						  ObjectIdGetDatum(MyDatabaseId), CStringGetDatum(subname));
 	if (!OidIsValid(oid) && !missing_ok)
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 153d2fde6fd..6fe268a8eec 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -6991,5 +6991,5 @@ ResOwnerReleaseRelation(Datum res)
 	Assert(rel->rd_refcnt > 0);
 	rel->rd_refcnt -= 1;
 
-	RelationCloseCleanup((Relation) res);
+	RelationCloseCleanup((Relation) DatumGetPointer(res));
 }
diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c
index f944453a1d8..7828bdcba8f 100644
--- a/src/backend/utils/cache/syscache.c
+++ b/src/backend/utils/cache/syscache.c
@@ -459,9 +459,9 @@ GetSysCacheOid(int cacheId,
 	tuple = SearchSysCache(cacheId, key1, key2, key3, key4);
 	if (!HeapTupleIsValid(tuple))
 		return InvalidOid;
-	result = heap_getattr(tuple, oidcol,
-						  SysCache[cacheId]->cc_tupdesc,
-						  &isNull);
+	result = DatumGetObjectId(heap_getattr(tuple, oidcol,
+										   SysCache[cacheId]->cc_tupdesc,
+										   &isNull));
 	Assert(!isNull);			/* columns used as oids should never be NULL */
 	ReleaseSysCache(tuple);
 	return result;
diff --git a/src/backend/utils/sort/sortsupport.c b/src/backend/utils/sort/sortsupport.c
index e0f500b9aa2..f582c6624f1 100644
--- a/src/backend/utils/sort/sortsupport.c
+++ b/src/backend/utils/sort/sortsupport.c
@@ -57,7 +57,7 @@ comparison_shim(Datum x, Datum y, SortSupport ssup)
 	if (extra->fcinfo.isnull)
 		elog(ERROR, "function %u returned NULL", extra->flinfo.fn_oid);
 
-	return result;
+	return DatumGetInt32(result);
 }
 
 /*
diff --git a/src/backend/utils/sort/tuplesortvariants.c b/src/backend/utils/sort/tuplesortvariants.c
index 5f70e8dddac..c5d18e46716 100644
--- a/src/backend/utils/sort/tuplesortvariants.c
+++ b/src/backend/utils/sort/tuplesortvariants.c
@@ -865,7 +865,7 @@ tuplesort_putbrintuple(Tuplesortstate *state, BrinTuple *tuple, Size size)
 	memcpy(&bstup->tuple, tuple, size);
 
 	stup.tuple = bstup;
-	stup.datum1 = tuple->bt_blkno;
+	stup.datum1 = UInt32GetDatum(tuple->bt_blkno);
 	stup.isnull1 = false;
 
 	/* GetMemoryChunkSpace is not supported for bump contexts */
@@ -1836,7 +1836,7 @@ removeabbrev_index_brin(Tuplesortstate *state, SortTuple *stups, int count)
 		BrinSortTuple *tuple;
 
 		tuple = stups[i].tuple;
-		stups[i].datum1 = tuple->tuple.bt_blkno;
+		stups[i].datum1 = UInt32GetDatum(tuple->tuple.bt_blkno);
 	}
 }
 
@@ -1893,7 +1893,7 @@ readtup_index_brin(Tuplesortstate *state, SortTuple *stup,
 	stup->tuple = tuple;
 
 	/* set up first-column key value, which is block number */
-	stup->datum1 = tuple->tuple.bt_blkno;
+	stup->datum1 = UInt32GetDatum(tuple->tuple.bt_blkno);
 }
 
 /*
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 29cb4d7e47f..73ba1748fe0 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1453,7 +1453,7 @@ plperl_sv_to_literal(SV *sv, char *fqtypename)
 
 	check_spi_usage_allowed();
 
-	typid = DirectFunctionCall1(regtypein, CStringGetDatum(fqtypename));
+	typid = DatumGetObjectId(DirectFunctionCall1(regtypein, CStringGetDatum(fqtypename)));
 	if (!OidIsValid(typid))
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
@@ -2569,13 +2569,13 @@ plperl_trigger_handler(PG_FUNCTION_ARGS)
 		TriggerData *trigdata = ((TriggerData *) fcinfo->context);
 
 		if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
-			retval = (Datum) trigdata->tg_trigtuple;
+			retval = PointerGetDatum(trigdata->tg_trigtuple);
 		else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
-			retval = (Datum) trigdata->tg_newtuple;
+			retval = PointerGetDatum(trigdata->tg_newtuple);
 		else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event))
-			retval = (Datum) trigdata->tg_trigtuple;
+			retval = PointerGetDatum(trigdata->tg_trigtuple);
 		else if (TRIGGER_FIRED_BY_TRUNCATE(trigdata->tg_event))
-			retval = (Datum) trigdata->tg_trigtuple;
+			retval = PointerGetDatum(trigdata->tg_trigtuple);
 		else
 			retval = (Datum) 0; /* can this happen? */
 	}
diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c
index 3dbba069024..465ac148ac9 100644
--- a/src/test/regress/regress.c
+++ b/src/test/regress/regress.c
@@ -727,7 +727,7 @@ PG_FUNCTION_INFO_V1(is_catalog_text_unique_index_oid);
 Datum
 is_catalog_text_unique_index_oid(PG_FUNCTION_ARGS)
 {
-	return IsCatalogTextUniqueIndexOid(PG_GETARG_OID(0));
+	return BoolGetDatum(IsCatalogTextUniqueIndexOid(PG_GETARG_OID(0)));
 }
 
 PG_FUNCTION_INFO_V1(test_support_func);
-- 
2.50.1

v1-0004-Fix-varatt-versus-Datum-type-confusions.patchtext/plain; charset=UTF-8; name=v1-0004-Fix-varatt-versus-Datum-type-confusions.patchDownload
From 8e2c5bbbb7bb28b500d92e923030c9cd8bc695be Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Thu, 31 Jul 2025 15:18:02 +0200
Subject: [PATCH v1 4/6] Fix varatt versus Datum type confusions

Macros like VARDATA() and VARSIZE() should be thought of as taking
values of type pointer to struct varlena or some other related struct.
The way they are implemented, you can pass anything to it and it will
cast it right.  But this is in principle incorrect.  To fix, add the
required DatumGetPointer() calls.
---
 contrib/hstore/hstore_gin.c                 |  2 +-
 contrib/hstore/hstore_gist.c                |  4 ++--
 contrib/hstore/hstore_io.c                  | 24 ++++++++++-----------
 contrib/hstore/hstore_op.c                  |  4 ++--
 contrib/test_decoding/test_decoding.c       |  2 +-
 src/backend/access/brin/brin_minmax_multi.c |  2 +-
 src/backend/access/common/heaptuple.c       |  2 +-
 src/backend/access/common/reloptions.c      |  8 +++----
 src/backend/access/common/toast_internals.c |  2 +-
 src/backend/access/gin/gininsert.c          |  2 +-
 src/backend/access/spgist/spgutils.c        |  4 ++--
 src/backend/access/table/toast_helper.c     |  2 +-
 src/backend/replication/logical/proto.c     |  2 +-
 src/backend/replication/pgoutput/pgoutput.c |  4 ++--
 src/backend/statistics/mcv.c                |  2 +-
 src/backend/tsearch/ts_selfuncs.c           |  2 +-
 src/backend/utils/adt/jsonb_gin.c           |  4 ++--
 src/backend/utils/adt/jsonb_op.c            |  8 +++----
 src/backend/utils/adt/jsonfuncs.c           |  4 ++--
 src/backend/utils/adt/jsonpath_exec.c       |  4 ++--
 src/backend/utils/adt/tsvector_op.c         | 24 ++++++++++-----------
 21 files changed, 56 insertions(+), 56 deletions(-)

diff --git a/contrib/hstore/hstore_gin.c b/contrib/hstore/hstore_gin.c
index 766c00bb6a7..2e5fa115924 100644
--- a/contrib/hstore/hstore_gin.c
+++ b/contrib/hstore/hstore_gin.c
@@ -127,7 +127,7 @@ gin_extract_hstore_query(PG_FUNCTION_ARGS)
 			/* Nulls in the array are ignored, cf hstoreArrayToPairs */
 			if (key_nulls[i])
 				continue;
-			item = makeitem(VARDATA(key_datums[i]), VARSIZE(key_datums[i]) - VARHDRSZ, KEYFLAG);
+			item = makeitem(VARDATA(DatumGetPointer(key_datums[i])), VARSIZE(DatumGetPointer(key_datums[i])) - VARHDRSZ, KEYFLAG);
 			entries[j++] = PointerGetDatum(item);
 		}
 
diff --git a/contrib/hstore/hstore_gist.c b/contrib/hstore/hstore_gist.c
index a3b08af3850..69515dc3d3f 100644
--- a/contrib/hstore/hstore_gist.c
+++ b/contrib/hstore/hstore_gist.c
@@ -576,7 +576,7 @@ ghstore_consistent(PG_FUNCTION_ARGS)
 
 			if (key_nulls[i])
 				continue;
-			crc = crc32_sz(VARDATA(key_datums[i]), VARSIZE(key_datums[i]) - VARHDRSZ);
+			crc = crc32_sz(VARDATA(DatumGetPointer(key_datums[i])), VARSIZE(DatumGetPointer(key_datums[i])) - VARHDRSZ);
 			if (!(GETBIT(sign, HASHVAL(crc, siglen))))
 				res = false;
 		}
@@ -599,7 +599,7 @@ ghstore_consistent(PG_FUNCTION_ARGS)
 
 			if (key_nulls[i])
 				continue;
-			crc = crc32_sz(VARDATA(key_datums[i]), VARSIZE(key_datums[i]) - VARHDRSZ);
+			crc = crc32_sz(VARDATA(DatumGetPointer(key_datums[i])), VARSIZE(DatumGetPointer(key_datums[i])) - VARHDRSZ);
 			if (GETBIT(sign, HASHVAL(crc, siglen)))
 				res = true;
 		}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index 4f867e4bd1f..9c53877c4a5 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -684,22 +684,22 @@ hstore_from_arrays(PG_FUNCTION_ARGS)
 
 		if (!value_nulls || value_nulls[i])
 		{
-			pairs[i].key = VARDATA(key_datums[i]);
+			pairs[i].key = VARDATA(DatumGetPointer(key_datums[i]));
 			pairs[i].val = NULL;
 			pairs[i].keylen =
-				hstoreCheckKeyLen(VARSIZE(key_datums[i]) - VARHDRSZ);
+				hstoreCheckKeyLen(VARSIZE(DatumGetPointer(key_datums[i])) - VARHDRSZ);
 			pairs[i].vallen = 4;
 			pairs[i].isnull = true;
 			pairs[i].needfree = false;
 		}
 		else
 		{
-			pairs[i].key = VARDATA(key_datums[i]);
-			pairs[i].val = VARDATA(value_datums[i]);
+			pairs[i].key = VARDATA(DatumGetPointer(key_datums[i]));
+			pairs[i].val = VARDATA(DatumGetPointer(value_datums[i]));
 			pairs[i].keylen =
-				hstoreCheckKeyLen(VARSIZE(key_datums[i]) - VARHDRSZ);
+				hstoreCheckKeyLen(VARSIZE(DatumGetPointer(key_datums[i])) - VARHDRSZ);
 			pairs[i].vallen =
-				hstoreCheckValLen(VARSIZE(value_datums[i]) - VARHDRSZ);
+				hstoreCheckValLen(VARSIZE(DatumGetPointer(value_datums[i])) - VARHDRSZ);
 			pairs[i].isnull = false;
 			pairs[i].needfree = false;
 		}
@@ -778,22 +778,22 @@ hstore_from_array(PG_FUNCTION_ARGS)
 
 		if (in_nulls[i * 2 + 1])
 		{
-			pairs[i].key = VARDATA(in_datums[i * 2]);
+			pairs[i].key = VARDATA(DatumGetPointer(in_datums[i * 2]));
 			pairs[i].val = NULL;
 			pairs[i].keylen =
-				hstoreCheckKeyLen(VARSIZE(in_datums[i * 2]) - VARHDRSZ);
+				hstoreCheckKeyLen(VARSIZE(DatumGetPointer(in_datums[i * 2])) - VARHDRSZ);
 			pairs[i].vallen = 4;
 			pairs[i].isnull = true;
 			pairs[i].needfree = false;
 		}
 		else
 		{
-			pairs[i].key = VARDATA(in_datums[i * 2]);
-			pairs[i].val = VARDATA(in_datums[i * 2 + 1]);
+			pairs[i].key = VARDATA(DatumGetPointer(in_datums[i * 2]));
+			pairs[i].val = VARDATA(DatumGetPointer(in_datums[i * 2 + 1]));
 			pairs[i].keylen =
-				hstoreCheckKeyLen(VARSIZE(in_datums[i * 2]) - VARHDRSZ);
+				hstoreCheckKeyLen(VARSIZE(DatumGetPointer(in_datums[i * 2])) - VARHDRSZ);
 			pairs[i].vallen =
-				hstoreCheckValLen(VARSIZE(in_datums[i * 2 + 1]) - VARHDRSZ);
+				hstoreCheckValLen(VARSIZE(DatumGetPointer(in_datums[i * 2 + 1])) - VARHDRSZ);
 			pairs[i].isnull = false;
 			pairs[i].needfree = false;
 		}
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index 5e57eceffc8..bcba75f9258 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -107,8 +107,8 @@ hstoreArrayToPairs(ArrayType *a, int *npairs)
 	{
 		if (!key_nulls[i])
 		{
-			key_pairs[j].key = VARDATA(key_datums[i]);
-			key_pairs[j].keylen = VARSIZE(key_datums[i]) - VARHDRSZ;
+			key_pairs[j].key = VARDATA(DatumGetPointer(key_datums[i]));
+			key_pairs[j].keylen = VARSIZE(DatumGetPointer(key_datums[i])) - VARHDRSZ;
 			key_pairs[j].val = NULL;
 			key_pairs[j].vallen = 0;
 			key_pairs[j].needfree = 0;
diff --git a/contrib/test_decoding/test_decoding.c b/contrib/test_decoding/test_decoding.c
index bb495563200..f671a7d4b31 100644
--- a/contrib/test_decoding/test_decoding.c
+++ b/contrib/test_decoding/test_decoding.c
@@ -581,7 +581,7 @@ tuple_to_stringinfo(StringInfo s, TupleDesc tupdesc, HeapTuple tuple, bool skip_
 		/* print data */
 		if (isnull)
 			appendStringInfoString(s, "null");
-		else if (typisvarlena && VARATT_IS_EXTERNAL_ONDISK(origval))
+		else if (typisvarlena && VARATT_IS_EXTERNAL_ONDISK(DatumGetPointer(origval)))
 			appendStringInfoString(s, "unchanged-toast-datum");
 		else if (!typisvarlena)
 			print_literal(s, typid,
diff --git a/src/backend/access/brin/brin_minmax_multi.c b/src/backend/access/brin/brin_minmax_multi.c
index 478e58b5bf2..e323c0447d0 100644
--- a/src/backend/access/brin/brin_minmax_multi.c
+++ b/src/backend/access/brin/brin_minmax_multi.c
@@ -624,7 +624,7 @@ brin_range_serialize(Ranges *range)
 
 		for (i = 0; i < nvalues; i++)
 		{
-			len += VARSIZE_ANY(range->values[i]);
+			len += VARSIZE_ANY(DatumGetPointer(range->values[i]));
 		}
 	}
 	else if (typlen == -2)		/* cstring */
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 09823a16358..1173a6d81b5 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -189,7 +189,7 @@ getmissingattr(TupleDesc tupleDesc,
 			if (att->attlen > 0)
 				key.len = att->attlen;
 			else
-				key.len = VARSIZE_ANY(attrmiss->am_value);
+				key.len = VARSIZE_ANY(DatumGetPointer(attrmiss->am_value));
 			key.value = attrmiss->am_value;
 
 			entry = hash_search(missing_cache, &key, HASH_ENTER, &found);
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 50747c16396..594a657ea1a 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -1190,8 +1190,8 @@ transformRelOptions(Datum oldOptions, List *defList, const char *namspace,
 
 		for (i = 0; i < noldoptions; i++)
 		{
-			char	   *text_str = VARDATA(oldoptions[i]);
-			int			text_len = VARSIZE(oldoptions[i]) - VARHDRSZ;
+			char	   *text_str = VARDATA(DatumGetPointer(oldoptions[i]));
+			int			text_len = VARSIZE(DatumGetPointer(oldoptions[i])) - VARHDRSZ;
 
 			/* Search for a match in defList */
 			foreach(cell, defList)
@@ -1456,8 +1456,8 @@ parseRelOptionsInternal(Datum options, bool validate,
 
 	for (i = 0; i < noptions; i++)
 	{
-		char	   *text_str = VARDATA(optiondatums[i]);
-		int			text_len = VARSIZE(optiondatums[i]) - VARHDRSZ;
+		char	   *text_str = VARDATA(DatumGetPointer(optiondatums[i]));
+		int			text_len = VARSIZE(DatumGetPointer(optiondatums[i])) - VARHDRSZ;
 		int			j;
 
 		/* Search for a match in reloptions */
diff --git a/src/backend/access/common/toast_internals.c b/src/backend/access/common/toast_internals.c
index 8d86c3b6ea6..a1d0eed8953 100644
--- a/src/backend/access/common/toast_internals.c
+++ b/src/backend/access/common/toast_internals.c
@@ -144,7 +144,7 @@ toast_save_datum(Relation rel, Datum value,
 	int			num_indexes;
 	int			validIndex;
 
-	Assert(!VARATT_IS_EXTERNAL(value));
+	Assert(!VARATT_IS_EXTERNAL(dval));
 
 	/*
 	 * Open the toast relation and its indexes.  We can use the index to check
diff --git a/src/backend/access/gin/gininsert.c b/src/backend/access/gin/gininsert.c
index a65acd89104..47b1898a064 100644
--- a/src/backend/access/gin/gininsert.c
+++ b/src/backend/access/gin/gininsert.c
@@ -2233,7 +2233,7 @@ _gin_build_tuple(OffsetNumber attrnum, unsigned char category,
 	else if (typlen > 0)
 		keylen = typlen;
 	else if (typlen == -1)
-		keylen = VARSIZE_ANY(key);
+		keylen = VARSIZE_ANY(DatumGetPointer(key));
 	else if (typlen == -2)
 		keylen = strlen(DatumGetPointer(key)) + 1;
 	else
diff --git a/src/backend/access/spgist/spgutils.c b/src/backend/access/spgist/spgutils.c
index 95fea74e296..9b86c016acb 100644
--- a/src/backend/access/spgist/spgutils.c
+++ b/src/backend/access/spgist/spgutils.c
@@ -785,7 +785,7 @@ SpGistGetInnerTypeSize(SpGistTypeDesc *att, Datum datum)
 	else if (att->attlen > 0)
 		size = att->attlen;
 	else
-		size = VARSIZE_ANY(datum);
+		size = VARSIZE_ANY(DatumGetPointer(datum));
 
 	return MAXALIGN(size);
 }
@@ -804,7 +804,7 @@ memcpyInnerDatum(void *target, SpGistTypeDesc *att, Datum datum)
 	}
 	else
 	{
-		size = (att->attlen > 0) ? att->attlen : VARSIZE_ANY(datum);
+		size = (att->attlen > 0) ? att->attlen : VARSIZE_ANY(DatumGetPointer(datum));
 		memcpy(target, DatumGetPointer(datum), size);
 	}
 }
diff --git a/src/backend/access/table/toast_helper.c b/src/backend/access/table/toast_helper.c
index b60fab0a4d2..11f97d65367 100644
--- a/src/backend/access/table/toast_helper.c
+++ b/src/backend/access/table/toast_helper.c
@@ -330,7 +330,7 @@ toast_delete_external(Relation rel, const Datum *values, const bool *isnull,
 
 			if (isnull[i])
 				continue;
-			else if (VARATT_IS_EXTERNAL_ONDISK(value))
+			else if (VARATT_IS_EXTERNAL_ONDISK(DatumGetPointer(value)))
 				toast_delete_datum(rel, value, is_speculative);
 		}
 	}
diff --git a/src/backend/replication/logical/proto.c b/src/backend/replication/logical/proto.c
index 1a352b542dc..1b3d9eb49dd 100644
--- a/src/backend/replication/logical/proto.c
+++ b/src/backend/replication/logical/proto.c
@@ -809,7 +809,7 @@ logicalrep_write_tuple(StringInfo out, Relation rel, TupleTableSlot *slot,
 			continue;
 		}
 
-		if (att->attlen == -1 && VARATT_IS_EXTERNAL_ONDISK(values[i]))
+		if (att->attlen == -1 && VARATT_IS_EXTERNAL_ONDISK(DatumGetPointer(values[i])))
 		{
 			/*
 			 * Unchanged toasted datum.  (Note that we don't promise to detect
diff --git a/src/backend/replication/pgoutput/pgoutput.c b/src/backend/replication/pgoutput/pgoutput.c
index f4c977262c5..80540c017bd 100644
--- a/src/backend/replication/pgoutput/pgoutput.c
+++ b/src/backend/replication/pgoutput/pgoutput.c
@@ -1374,8 +1374,8 @@ pgoutput_row_filter(Relation relation, TupleTableSlot *old_slot,
 		 * VARTAG_INDIRECT. See ReorderBufferToastReplace.
 		 */
 		if (att->attlen == -1 &&
-			VARATT_IS_EXTERNAL_ONDISK(new_slot->tts_values[i]) &&
-			!VARATT_IS_EXTERNAL_ONDISK(old_slot->tts_values[i]))
+			VARATT_IS_EXTERNAL_ONDISK(DatumGetPointer(new_slot->tts_values[i])) &&
+			!VARATT_IS_EXTERNAL_ONDISK(DatumGetPointer(old_slot->tts_values[i])))
 		{
 			if (!tmp_new_slot)
 			{
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index d98cda698d9..f59fb821543 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -767,7 +767,7 @@ statext_mcv_serialize(MCVList *mcvlist, VacAttrStats **stats)
 				values[dim][i] = PointerGetDatum(PG_DETOAST_DATUM(values[dim][i]));
 
 				/* serialized length (uint32 length + data) */
-				len = VARSIZE_ANY_EXHDR(values[dim][i]);
+				len = VARSIZE_ANY_EXHDR(DatumGetPointer(values[dim][i]));
 				info[dim].nbytes += sizeof(uint32); /* length */
 				info[dim].nbytes += len;	/* value (no header) */
 
diff --git a/src/backend/tsearch/ts_selfuncs.c b/src/backend/tsearch/ts_selfuncs.c
index 0c1d2bc1109..453a5e5c2ea 100644
--- a/src/backend/tsearch/ts_selfuncs.c
+++ b/src/backend/tsearch/ts_selfuncs.c
@@ -233,7 +233,7 @@ mcelem_tsquery_selec(TSQuery query, Datum *mcelem, int nmcelem,
 		 * The text Datums came from an array, so it cannot be compressed or
 		 * stored out-of-line -- it's safe to use VARSIZE_ANY*.
 		 */
-		Assert(!VARATT_IS_COMPRESSED(mcelem[i]) && !VARATT_IS_EXTERNAL(mcelem[i]));
+		Assert(!VARATT_IS_COMPRESSED(DatumGetPointer(mcelem[i])) && !VARATT_IS_EXTERNAL(DatumGetPointer(mcelem[i])));
 		lookup[i].element = (text *) DatumGetPointer(mcelem[i]);
 		lookup[i].frequency = numbers[i];
 	}
diff --git a/src/backend/utils/adt/jsonb_gin.c b/src/backend/utils/adt/jsonb_gin.c
index c1950792b5a..9b56248cf0b 100644
--- a/src/backend/utils/adt/jsonb_gin.c
+++ b/src/backend/utils/adt/jsonb_gin.c
@@ -896,8 +896,8 @@ gin_extract_jsonb_query(PG_FUNCTION_ARGS)
 				continue;
 			/* We rely on the array elements not being toasted */
 			entries[j++] = make_text_key(JGINFLAG_KEY,
-										 VARDATA_ANY(key_datums[i]),
-										 VARSIZE_ANY_EXHDR(key_datums[i]));
+										 VARDATA_ANY(DatumGetPointer(key_datums[i])),
+										 VARSIZE_ANY_EXHDR(DatumGetPointer(key_datums[i])));
 		}
 
 		*nentries = j;
diff --git a/src/backend/utils/adt/jsonb_op.c b/src/backend/utils/adt/jsonb_op.c
index fa5603f26e1..51d38e321fb 100644
--- a/src/backend/utils/adt/jsonb_op.c
+++ b/src/backend/utils/adt/jsonb_op.c
@@ -63,8 +63,8 @@ jsonb_exists_any(PG_FUNCTION_ARGS)
 
 		strVal.type = jbvString;
 		/* We rely on the array elements not being toasted */
-		strVal.val.string.val = VARDATA_ANY(key_datums[i]);
-		strVal.val.string.len = VARSIZE_ANY_EXHDR(key_datums[i]);
+		strVal.val.string.val = VARDATA_ANY(DatumGetPointer(key_datums[i]));
+		strVal.val.string.len = VARSIZE_ANY_EXHDR(DatumGetPointer(key_datums[i]));
 
 		if (findJsonbValueFromContainer(&jb->root,
 										JB_FOBJECT | JB_FARRAY,
@@ -96,8 +96,8 @@ jsonb_exists_all(PG_FUNCTION_ARGS)
 
 		strVal.type = jbvString;
 		/* We rely on the array elements not being toasted */
-		strVal.val.string.val = VARDATA_ANY(key_datums[i]);
-		strVal.val.string.len = VARSIZE_ANY_EXHDR(key_datums[i]);
+		strVal.val.string.val = VARDATA_ANY(DatumGetPointer(key_datums[i]));
+		strVal.val.string.len = VARSIZE_ANY_EXHDR(DatumGetPointer(key_datums[i]));
 
 		if (findJsonbValueFromContainer(&jb->root,
 										JB_FOBJECT | JB_FARRAY,
diff --git a/src/backend/utils/adt/jsonfuncs.c b/src/backend/utils/adt/jsonfuncs.c
index bcb1720b6cd..370456408bf 100644
--- a/src/backend/utils/adt/jsonfuncs.c
+++ b/src/backend/utils/adt/jsonfuncs.c
@@ -4766,8 +4766,8 @@ jsonb_delete_array(PG_FUNCTION_ARGS)
 					continue;
 
 				/* We rely on the array elements not being toasted */
-				keyptr = VARDATA_ANY(keys_elems[i]);
-				keylen = VARSIZE_ANY_EXHDR(keys_elems[i]);
+				keyptr = VARDATA_ANY(DatumGetPointer(keys_elems[i]));
+				keylen = VARSIZE_ANY_EXHDR(DatumGetPointer(keys_elems[i]));
 				if (keylen == v.val.string.len &&
 					memcmp(keyptr, v.val.string.val, keylen) == 0)
 				{
diff --git a/src/backend/utils/adt/jsonpath_exec.c b/src/backend/utils/adt/jsonpath_exec.c
index 21c2cf3c71d..5a562535223 100644
--- a/src/backend/utils/adt/jsonpath_exec.c
+++ b/src/backend/utils/adt/jsonpath_exec.c
@@ -3074,8 +3074,8 @@ JsonItemFromDatum(Datum val, Oid typid, int32 typmod, JsonbValue *res)
 		case TEXTOID:
 		case VARCHAROID:
 			res->type = jbvString;
-			res->val.string.val = VARDATA_ANY(val);
-			res->val.string.len = VARSIZE_ANY_EXHDR(val);
+			res->val.string.val = VARDATA_ANY(DatumGetPointer(val));
+			res->val.string.len = VARSIZE_ANY_EXHDR(DatumGetPointer(val));
 			break;
 		case DATEOID:
 		case TIMEOID:
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 1fa1275ca63..0625da9532f 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -329,8 +329,8 @@ tsvector_setweight_by_filter(PG_FUNCTION_ARGS)
 		if (nulls[i])
 			continue;
 
-		lex = VARDATA(dlexemes[i]);
-		lex_len = VARSIZE(dlexemes[i]) - VARHDRSZ;
+		lex = VARDATA(DatumGetPointer(dlexemes[i]));
+		lex_len = VARSIZE(DatumGetPointer(dlexemes[i])) - VARHDRSZ;
 		lex_pos = tsvector_bsearch(tsout, lex, lex_len);
 
 		if (lex_pos >= 0 && (j = POSDATALEN(tsout, entry + lex_pos)) != 0)
@@ -443,10 +443,10 @@ compare_text_lexemes(const void *va, const void *vb)
 {
 	Datum		a = *((const Datum *) va);
 	Datum		b = *((const Datum *) vb);
-	char	   *alex = VARDATA_ANY(a);
-	int			alex_len = VARSIZE_ANY_EXHDR(a);
-	char	   *blex = VARDATA_ANY(b);
-	int			blex_len = VARSIZE_ANY_EXHDR(b);
+	char	   *alex = VARDATA_ANY(DatumGetPointer(a));
+	int			alex_len = VARSIZE_ANY_EXHDR(DatumGetPointer(a));
+	char	   *blex = VARDATA_ANY(DatumGetPointer(b));
+	int			blex_len = VARSIZE_ANY_EXHDR(DatumGetPointer(b));
 
 	return tsCompareString(alex, alex_len, blex, blex_len, false);
 }
@@ -605,8 +605,8 @@ tsvector_delete_arr(PG_FUNCTION_ARGS)
 		if (nulls[i])
 			continue;
 
-		lex = VARDATA(dlexemes[i]);
-		lex_len = VARSIZE(dlexemes[i]) - VARHDRSZ;
+		lex = VARDATA(DatumGetPointer(dlexemes[i]));
+		lex_len = VARSIZE(DatumGetPointer(dlexemes[i])) - VARHDRSZ;
 		lex_pos = tsvector_bsearch(tsin, lex, lex_len);
 
 		if (lex_pos >= 0)
@@ -770,7 +770,7 @@ array_to_tsvector(PG_FUNCTION_ARGS)
 					(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
 					 errmsg("lexeme array may not contain nulls")));
 
-		if (VARSIZE(dlexemes[i]) - VARHDRSZ == 0)
+		if (VARSIZE(DatumGetPointer(dlexemes[i])) - VARHDRSZ == 0)
 			ereport(ERROR,
 					(errcode(ERRCODE_ZERO_LENGTH_CHARACTER_STRING),
 					 errmsg("lexeme array may not contain empty strings")));
@@ -786,7 +786,7 @@ array_to_tsvector(PG_FUNCTION_ARGS)
 
 	/* Calculate space needed for surviving lexemes. */
 	for (i = 0; i < nitems; i++)
-		datalen += VARSIZE(dlexemes[i]) - VARHDRSZ;
+		datalen += VARSIZE(DatumGetPointer(dlexemes[i])) - VARHDRSZ;
 	tslen = CALCDATASIZE(nitems, datalen);
 
 	/* Allocate and fill tsvector. */
@@ -798,8 +798,8 @@ array_to_tsvector(PG_FUNCTION_ARGS)
 	cur = STRPTR(tsout);
 	for (i = 0; i < nitems; i++)
 	{
-		char	   *lex = VARDATA(dlexemes[i]);
-		int			lex_len = VARSIZE(dlexemes[i]) - VARHDRSZ;
+		char	   *lex = VARDATA(DatumGetPointer(dlexemes[i]));
+		int			lex_len = VARSIZE(DatumGetPointer(dlexemes[i])) - VARHDRSZ;
 
 		memcpy(cur, lex, lex_len);
 		arrout[i].haspos = 0;
-- 
2.50.1

v1-0005-Fix-various-hash-function-uses.patchtext/plain; charset=UTF-8; name=v1-0005-Fix-various-hash-function-uses.patchDownload
From dfd9e4b16e979ac52be682d8c093f883da8d7ba2 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Thu, 31 Jul 2025 15:18:02 +0200
Subject: [PATCH v1 5/6] Fix various hash function uses

These instances were using Datum-returning functions where a
lower-level function returning uint32 would be more appropriate.
---
 contrib/sepgsql/uavc.c                  | 4 ++--
 src/backend/access/common/tupdesc.c     | 6 +++---
 src/backend/storage/file/fileset.c      | 2 +-
 src/backend/utils/adt/multirangetypes.c | 2 +-
 src/backend/utils/adt/rangetypes.c      | 2 +-
 src/backend/utils/cache/catcache.c      | 2 +-
 6 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/contrib/sepgsql/uavc.c b/contrib/sepgsql/uavc.c
index 65ea8e7946a..d9ccbc38bc5 100644
--- a/contrib/sepgsql/uavc.c
+++ b/contrib/sepgsql/uavc.c
@@ -66,8 +66,8 @@ static char *avc_unlabeled;		/* system 'unlabeled' label */
 static uint32
 sepgsql_avc_hash(const char *scontext, const char *tcontext, uint16 tclass)
 {
-	return hash_any((const unsigned char *) scontext, strlen(scontext))
-		^ hash_any((const unsigned char *) tcontext, strlen(tcontext))
+	return hash_bytes((const unsigned char *) scontext, strlen(scontext))
+		^ hash_bytes((const unsigned char *) tcontext, strlen(tcontext))
 		^ tclass;
 }
 
diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c
index 020d00cd01c..be60005ae46 100644
--- a/src/backend/access/common/tupdesc.c
+++ b/src/backend/access/common/tupdesc.c
@@ -815,10 +815,10 @@ hashRowType(TupleDesc desc)
 	uint32		s;
 	int			i;
 
-	s = hash_combine(0, hash_uint32(desc->natts));
-	s = hash_combine(s, hash_uint32(desc->tdtypeid));
+	s = hash_combine(0, hash_bytes_uint32(desc->natts));
+	s = hash_combine(s, hash_bytes_uint32(desc->tdtypeid));
 	for (i = 0; i < desc->natts; ++i)
-		s = hash_combine(s, hash_uint32(TupleDescAttr(desc, i)->atttypid));
+		s = hash_combine(s, hash_bytes_uint32(TupleDescAttr(desc, i)->atttypid));
 
 	return s;
 }
diff --git a/src/backend/storage/file/fileset.c b/src/backend/storage/file/fileset.c
index 64141c7cb91..4d5ee353fd7 100644
--- a/src/backend/storage/file/fileset.c
+++ b/src/backend/storage/file/fileset.c
@@ -185,7 +185,7 @@ FileSetPath(char *path, FileSet *fileset, Oid tablespace)
 static Oid
 ChooseTablespace(const FileSet *fileset, const char *name)
 {
-	uint32		hash = hash_any((const unsigned char *) name, strlen(name));
+	uint32		hash = hash_bytes((const unsigned char *) name, strlen(name));
 
 	return fileset->tablespaces[hash % fileset->ntablespaces];
 }
diff --git a/src/backend/utils/adt/multirangetypes.c b/src/backend/utils/adt/multirangetypes.c
index 4c3db172e76..097f91d2346 100644
--- a/src/backend/utils/adt/multirangetypes.c
+++ b/src/backend/utils/adt/multirangetypes.c
@@ -2833,7 +2833,7 @@ hash_multirange(PG_FUNCTION_ARGS)
 			upper_hash = 0;
 
 		/* Merge hashes of flags and bounds */
-		range_hash = hash_uint32((uint32) flags);
+		range_hash = hash_bytes_uint32((uint32) flags);
 		range_hash ^= lower_hash;
 		range_hash = pg_rotate_left32(range_hash, 1);
 		range_hash ^= upper_hash;
diff --git a/src/backend/utils/adt/rangetypes.c b/src/backend/utils/adt/rangetypes.c
index f26dbfa4c97..15398c72ea0 100644
--- a/src/backend/utils/adt/rangetypes.c
+++ b/src/backend/utils/adt/rangetypes.c
@@ -1442,7 +1442,7 @@ hash_range(PG_FUNCTION_ARGS)
 		upper_hash = 0;
 
 	/* Merge hashes of flags and bounds */
-	result = hash_uint32((uint32) flags);
+	result = hash_bytes_uint32((uint32) flags);
 	result ^= lower_hash;
 	result = pg_rotate_left32(result, 1);
 	result ^= upper_hash;
diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c
index d1b25214376..e2cd3feaf81 100644
--- a/src/backend/utils/cache/catcache.c
+++ b/src/backend/utils/cache/catcache.c
@@ -213,7 +213,7 @@ namehashfast(Datum datum)
 {
 	char	   *key = NameStr(*DatumGetName(datum));
 
-	return hash_any((unsigned char *) key, strlen(key));
+	return hash_bytes((unsigned char *) key, strlen(key));
 }
 
 static bool
-- 
2.50.1

v1-0006-WIP-Datum-as-struct.patchtext/plain; charset=UTF-8; name=v1-0006-WIP-Datum-as-struct.patchDownload
From 81e56922fe429fae6ebc33b2f518ef88b00ffc42 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Thu, 31 Jul 2025 15:18:02 +0200
Subject: [PATCH v1 6/6] WIP: Datum as struct

This changes Datum to a struct so that you can no longer rely on it
being implicitly convertable to other C types.
---
 contrib/btree_gin/btree_gin.c                 |  2 +-
 contrib/dblink/dblink.c                       |  8 +--
 contrib/hstore/hstore_io.c                    |  2 +-
 contrib/hstore/hstore_op.c                    |  8 +--
 contrib/intarray/_int_bool.c                  |  4 +-
 contrib/ltree/_ltree_gist.c                   |  2 +-
 contrib/ltree/ltree_gist.c                    |  2 +-
 contrib/pageinspect/brinfuncs.c               |  2 +-
 contrib/pageinspect/gistfuncs.c               |  6 +-
 contrib/pg_buffercache/pg_buffercache_pages.c |  2 +-
 contrib/pg_prewarm/autoprewarm.c              |  6 +-
 .../pg_stat_statements/pg_stat_statements.c   | 20 +++---
 contrib/pgrowlocks/pgrowlocks.c               |  2 +-
 contrib/pgstattuple/pgstattuple.c             |  2 +-
 contrib/postgres_fdw/connection.c             |  4 +-
 contrib/postgres_fdw/postgres_fdw.c           |  2 +-
 contrib/postgres_fdw/shippable.c              |  2 +-
 contrib/seg/seg.c                             |  2 +-
 contrib/sepgsql/label.c                       |  2 +-
 contrib/sepgsql/uavc.c                        |  2 +-
 contrib/spi/moddatetime.c                     |  2 +-
 contrib/sslinfo/sslinfo.c                     |  6 +-
 contrib/tablefunc/tablefunc.c                 |  8 +--
 contrib/xml2/xpath.c                          |  2 +-
 src/backend/access/brin/brin_bloom.c          |  4 +-
 src/backend/access/brin/brin_inclusion.c      |  4 +-
 src/backend/access/brin/brin_minmax.c         |  2 +-
 src/backend/access/brin/brin_minmax_multi.c   |  2 +-
 src/backend/access/common/heaptuple.c         |  6 +-
 src/backend/access/common/indextuple.c        |  2 +-
 src/backend/access/common/reloptions.c        |  6 +-
 src/backend/access/common/tupconvert.c        |  6 +-
 src/backend/access/gin/gininsert.c            |  6 +-
 src/backend/access/gin/ginscan.c              |  4 +-
 src/backend/access/gin/ginutil.c              |  4 +-
 src/backend/access/gist/gistproc.c            | 10 +--
 src/backend/access/gist/gistutil.c            | 16 ++---
 src/backend/access/index/indexam.c            |  4 +-
 src/backend/access/nbtree/nbtcompare.c        | 24 +++----
 src/backend/access/nbtree/nbtpreprocesskeys.c |  2 +-
 src/backend/access/nbtree/nbtree.c            | 12 ++--
 src/backend/access/nbtree/nbtsearch.c         |  2 +-
 src/backend/access/nbtree/nbtutils.c          | 20 +++---
 src/backend/access/spgist/spgdoinsert.c       | 16 ++---
 src/backend/access/spgist/spgscan.c           | 12 ++--
 src/backend/access/spgist/spgutils.c          |  2 +-
 src/backend/access/transam/rmgr.c             |  2 +-
 src/backend/access/transam/twophase.c         |  4 +-
 src/backend/access/transam/xlogprefetcher.c   |  2 +-
 src/backend/backup/walsummaryfuncs.c          |  4 +-
 src/backend/bootstrap/bootparse.y             |  2 +-
 src/backend/catalog/aclchk.c                  | 14 ++--
 src/backend/catalog/heap.c                    | 12 ++--
 src/backend/catalog/index.c                   | 12 ++--
 src/backend/catalog/namespace.c               | 10 +--
 src/backend/catalog/pg_aggregate.c            |  2 +-
 src/backend/catalog/pg_constraint.c           |  2 +-
 src/backend/catalog/pg_conversion.c           |  2 +-
 src/backend/catalog/pg_namespace.c            |  2 +-
 src/backend/catalog/pg_operator.c             |  4 +-
 src/backend/catalog/pg_proc.c                 | 18 ++---
 src/backend/catalog/pg_type.c                 |  4 +-
 src/backend/catalog/toasting.c                |  6 +-
 src/backend/commands/analyze.c                |  6 +-
 src/backend/commands/async.c                  |  2 +-
 src/backend/commands/cluster.c                |  4 +-
 src/backend/commands/createas.c               |  2 +-
 src/backend/commands/event_trigger.c          |  2 +-
 src/backend/commands/extension.c              | 16 ++---
 src/backend/commands/functioncmds.c           |  4 +-
 src/backend/commands/indexcmds.c              | 18 ++---
 src/backend/commands/operatorcmds.c           |  2 +-
 src/backend/commands/prepare.c                |  2 +-
 src/backend/commands/statscmds.c              |  4 +-
 src/backend/commands/tablecmds.c              | 22 +++---
 src/backend/commands/tablespace.c             |  8 +--
 src/backend/commands/trigger.c                |  2 +-
 src/backend/commands/tsearchcmds.c            |  2 +-
 src/backend/commands/user.c                   |  2 +-
 src/backend/executor/execExpr.c               |  6 +-
 src/backend/executor/execExprInterp.c         | 68 +++++++++----------
 src/backend/executor/execJunk.c               |  2 +-
 src/backend/executor/execSRF.c                |  6 +-
 src/backend/executor/execTuples.c             |  8 +--
 src/backend/executor/execUtils.c              | 14 ++--
 src/backend/executor/functions.c              | 12 ++--
 src/backend/executor/nodeAgg.c                | 24 +++----
 src/backend/executor/nodeFunctionscan.c       |  2 +-
 src/backend/executor/nodeIndexscan.c          | 12 ++--
 src/backend/executor/nodeProjectSet.c         |  2 +-
 src/backend/executor/nodeSubplan.c            |  8 +--
 src/backend/executor/nodeWindowAgg.c          | 16 ++---
 src/backend/executor/spi.c                    |  2 +-
 src/backend/foreign/foreign.c                 |  4 +-
 src/backend/jit/llvm/llvmjit.c                |  2 +-
 src/backend/jit/llvm/llvmjit_expr.c           |  4 +-
 src/backend/libpq/pqcomm.c                    |  2 +-
 src/backend/libpq/pqmq.c                      |  2 +-
 src/backend/nodes/makefuncs.c                 |  2 +-
 src/backend/nodes/readfuncs.c                 |  4 +-
 src/backend/optimizer/prep/prepagg.c          |  2 +-
 src/backend/optimizer/prep/preptlist.c        |  4 +-
 src/backend/optimizer/util/predtest.c         |  2 +-
 src/backend/parser/parse_coerce.c             |  2 +-
 src/backend/parser/parse_expr.c               |  4 +-
 src/backend/parser/parse_node.c               |  2 +-
 src/backend/parser/parse_oper.c               |  4 +-
 src/backend/parser/parse_utilcmd.c            |  2 +-
 src/backend/partitioning/partbounds.c         |  4 +-
 src/backend/port/posix_sema.c                 |  2 +-
 src/backend/port/sysv_sema.c                  |  2 +-
 src/backend/port/sysv_shmem.c                 |  2 +-
 src/backend/port/win32_sema.c                 |  2 +-
 src/backend/postmaster/autovacuum.c           |  2 +-
 src/backend/postmaster/auxprocess.c           |  2 +-
 src/backend/postmaster/checkpointer.c         |  4 +-
 src/backend/postmaster/pgarch.c               |  4 +-
 src/backend/postmaster/postmaster.c           |  4 +-
 src/backend/postmaster/startup.c              |  2 +-
 src/backend/postmaster/walsummarizer.c        |  2 +-
 .../replication/logical/applyparallelworker.c |  2 +-
 src/backend/replication/logical/launcher.c    |  8 +--
 .../replication/logical/logicalfuncs.c        |  2 +-
 src/backend/replication/logical/origin.c      |  4 +-
 src/backend/replication/logical/relation.c    |  4 +-
 src/backend/replication/logical/slotsync.c    |  2 +-
 src/backend/replication/logical/worker.c      | 16 ++---
 src/backend/replication/pgoutput/pgoutput.c   | 10 +--
 src/backend/replication/slot.c                |  2 +-
 src/backend/replication/slotfuncs.c           |  2 +-
 src/backend/replication/walsender.c           |  4 +-
 src/backend/statistics/attribute_stats.c      | 14 ++--
 src/backend/statistics/extended_stats.c       | 14 ++--
 src/backend/statistics/mcv.c                  |  4 +-
 src/backend/statistics/stat_utils.c           |  2 +-
 src/backend/storage/aio/aio_funcs.c           |  2 +-
 src/backend/storage/aio/aio_init.c            |  2 +-
 src/backend/storage/aio/method_worker.c       |  2 +-
 src/backend/storage/buffer/bufmgr.c           |  2 +-
 src/backend/storage/file/fd.c                 |  2 +-
 src/backend/storage/ipc/dsm.c                 |  2 +-
 src/backend/storage/ipc/dsm_registry.c        |  2 +-
 src/backend/storage/ipc/ipc.c                 |  4 +-
 src/backend/storage/ipc/pmsignal.c            |  2 +-
 src/backend/storage/ipc/procsignal.c          |  2 +-
 src/backend/storage/ipc/shmem.c               |  4 +-
 src/backend/storage/lmgr/predicate.c          | 18 +++--
 src/backend/storage/lmgr/proc.c               |  4 +-
 src/backend/storage/smgr/smgr.c               |  2 +-
 src/backend/tcop/fastpath.c                   |  2 +-
 src/backend/tcop/postgres.c                   |  4 +-
 src/backend/tcop/utility.c                    |  2 +-
 src/backend/tsearch/ts_typanalyze.c           |  2 +-
 src/backend/tsearch/wparser.c                 | 18 +++--
 src/backend/utils/activity/backend_status.c   |  2 +-
 src/backend/utils/activity/pgstat.c           |  2 +-
 src/backend/utils/activity/pgstat_shmem.c     |  4 +-
 src/backend/utils/activity/wait_event_funcs.c |  2 +-
 src/backend/utils/adt/acl.c                   |  8 +--
 src/backend/utils/adt/array_selfuncs.c        |  2 +-
 src/backend/utils/adt/array_typanalyze.c      |  2 +-
 src/backend/utils/adt/array_userfuncs.c       | 18 ++---
 src/backend/utils/adt/arrayfuncs.c            | 42 ++++++------
 src/backend/utils/adt/arraysubs.c             |  4 +-
 src/backend/utils/adt/bool.c                  |  2 +-
 src/backend/utils/adt/bytea.c                 |  2 +-
 src/backend/utils/adt/cash.c                  | 10 +--
 src/backend/utils/adt/date.c                  |  8 +--
 src/backend/utils/adt/datetime.c              |  2 +-
 src/backend/utils/adt/datum.c                 |  6 +-
 src/backend/utils/adt/enum.c                  |  4 +-
 src/backend/utils/adt/expandedrecord.c        |  8 +--
 src/backend/utils/adt/formatting.c            | 22 +++---
 src/backend/utils/adt/genfile.c               |  8 +--
 src/backend/utils/adt/geo_ops.c               | 22 +++---
 src/backend/utils/adt/int.c                   |  6 +-
 src/backend/utils/adt/json.c                  |  4 +-
 src/backend/utils/adt/jsonb.c                 |  6 +-
 src/backend/utils/adt/jsonb_gin.c             |  2 +-
 src/backend/utils/adt/jsonbsubs.c             |  2 +-
 src/backend/utils/adt/jsonfuncs.c             | 38 +++++------
 src/backend/utils/adt/jsonpath.c              |  6 +-
 src/backend/utils/adt/jsonpath_exec.c         |  6 +-
 src/backend/utils/adt/mac.c                   | 10 +--
 src/backend/utils/adt/mac8.c                  |  2 +-
 src/backend/utils/adt/mcxtfuncs.c             |  2 +-
 src/backend/utils/adt/misc.c                  |  6 +-
 src/backend/utils/adt/multirangetypes.c       | 14 ++--
 src/backend/utils/adt/network.c               | 38 +++++------
 src/backend/utils/adt/network_gist.c          |  2 +-
 src/backend/utils/adt/numeric.c               | 12 ++--
 src/backend/utils/adt/orderedsetaggs.c        | 26 +++----
 src/backend/utils/adt/pg_lsn.c                |  2 +-
 src/backend/utils/adt/pgstatfuncs.c           | 12 ++--
 src/backend/utils/adt/rangetypes.c            | 36 +++++-----
 src/backend/utils/adt/regexp.c                |  2 +-
 src/backend/utils/adt/regproc.c               | 36 +++++-----
 src/backend/utils/adt/ri_triggers.c           |  2 +-
 src/backend/utils/adt/rowtypes.c              | 10 +--
 src/backend/utils/adt/ruleutils.c             |  2 +-
 src/backend/utils/adt/selfuncs.c              |  6 +-
 src/backend/utils/adt/tid.c                   |  8 +--
 src/backend/utils/adt/timestamp.c             | 10 +--
 src/backend/utils/adt/tsvector.c              |  6 +-
 src/backend/utils/adt/tsvector_op.c           |  8 ++-
 src/backend/utils/adt/uuid.c                  | 10 +--
 src/backend/utils/adt/varbit.c                | 16 ++---
 src/backend/utils/adt/varlena.c               | 22 +++---
 src/backend/utils/adt/xml.c                   | 26 +++----
 src/backend/utils/cache/attoptcache.c         |  2 +-
 src/backend/utils/cache/catcache.c            | 16 ++---
 src/backend/utils/cache/evtcache.c            |  2 +-
 src/backend/utils/cache/lsyscache.c           |  2 +-
 src/backend/utils/cache/plancache.c           | 16 ++---
 src/backend/utils/cache/relcache.c            |  4 +-
 src/backend/utils/cache/relfilenumbermap.c    |  2 +-
 src/backend/utils/cache/spccache.c            |  2 +-
 src/backend/utils/cache/typcache.c            | 10 +--
 src/backend/utils/fmgr/fmgr.c                 |  8 +--
 src/backend/utils/fmgr/funcapi.c              | 12 ++--
 src/backend/utils/init/miscinit.c             |  2 +-
 src/backend/utils/init/postinit.c             |  6 +-
 src/backend/utils/misc/guc_funcs.c            |  2 +-
 src/backend/utils/misc/pg_config.c            |  2 +-
 src/backend/utils/misc/superuser.c            |  2 +-
 src/backend/utils/mmgr/portalmem.c            |  2 +-
 src/backend/utils/resowner/resowner.c         | 14 ++--
 src/backend/utils/sort/tuplesort.c            |  4 +-
 src/backend/utils/sort/tuplesortvariants.c    |  8 +--
 src/include/access/gin.h                      |  4 +-
 src/include/access/htup_details.h             |  2 +-
 src/include/access/itup.h                     |  2 +-
 src/include/access/spgist_private.h           |  2 +-
 src/include/access/tupmacs.h                  |  2 +-
 src/include/executor/executor.h               |  2 +-
 src/include/fmgr.h                            |  6 +-
 src/include/nodes/nodes.h                     |  6 +-
 src/include/port/pg_bswap.h                   |  6 +-
 src/include/postgres.h                        | 61 +++++++++--------
 src/include/utils/arrayaccess.h               |  2 +-
 src/include/utils/sortsupport.h               |  2 +-
 src/include/utils/syscache.h                  | 28 ++++----
 src/pl/plperl/plperl.c                        | 12 ++--
 src/pl/plpgsql/src/pl_comp.c                  |  2 +-
 src/pl/plpgsql/src/pl_exec.c                  | 40 +++++------
 src/pl/plpgsql/src/pl_handler.c               |  2 +-
 src/pl/plpython/plpy_exec.c                   |  4 +-
 src/pl/plpython/plpy_typeio.c                 | 20 +++---
 src/pl/tcl/pltcl.c                            |  6 +-
 .../injection_points/injection_points.c       |  4 +-
 .../injection_points/injection_stats.c        |  2 +-
 src/test/modules/plsample/plsample.c          |  2 +-
 .../test_ddl_deparse/test_ddl_deparse.c       |  2 +-
 src/test/modules/test_regex/test_regex.c      |  2 +-
 254 files changed, 915 insertions(+), 892 deletions(-)

diff --git a/contrib/btree_gin/btree_gin.c b/contrib/btree_gin/btree_gin.c
index 8c477d17e22..5125232376e 100644
--- a/contrib/btree_gin/btree_gin.c
+++ b/contrib/btree_gin/btree_gin.c
@@ -166,7 +166,7 @@ gin_btree_compare_prefix(FunctionCallInfo fcinfo)
 	 * we'll notice if anyone ever changes the core code in a way that breaks
 	 * our assumptions.
 	 */
-	Assert(partial_key == data->entry_datum);
+	Assert(partial_key.value == data->entry_datum.value);
 
 	cmp = DatumGetInt32(CallerFInfoFunctionCall2(data->typecmp,
 												 fcinfo->flinfo,
diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index f98805fb5f7..e56e0db97c9 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -653,7 +653,7 @@ dblink_fetch(PG_FUNCTION_ARGS)
 	{
 		dblink_res_error(conn, conname, res, fail,
 						 "while fetching from cursor \"%s\"", curname);
-		return (Datum) 0;
+		PG_RETURN_DUMMY();
 	}
 	else if (PQresultStatus(res) == PGRES_COMMAND_OK)
 	{
@@ -665,7 +665,7 @@ dblink_fetch(PG_FUNCTION_ARGS)
 	}
 
 	materializeResult(fcinfo, conn, res);
-	return (Datum) 0;
+	PG_RETURN_DUMMY();
 }
 
 /*
@@ -821,7 +821,7 @@ dblink_record_internal(FunctionCallInfo fcinfo, bool is_async)
 	}
 	PG_END_TRY();
 
-	return (Datum) 0;
+	PG_RETURN_DUMMY();
 }
 
 /*
@@ -1915,7 +1915,7 @@ dblink_get_notify(PG_FUNCTION_ARGS)
 		PQconsumeInput(conn);
 	}
 
-	return (Datum) 0;
+	PG_RETURN_DUMMY();
 }
 
 /*
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index 9c53877c4a5..d059b31231f 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1113,7 +1113,7 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	{
 		for (i = 0; i < ncolumns; ++i)
 		{
-			values[i] = (Datum) 0;
+			values[i] = DummyDatum;
 			nulls[i] = true;
 		}
 	}
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index bcba75f9258..b22c4b32827 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -604,7 +604,7 @@ hstore_slice_to_array(PG_FUNCTION_ARGS)
 		if (idx < 0 || HSTORE_VALISNULL(entries, idx))
 		{
 			out_nulls[i] = true;
-			out_datums[i] = (Datum) 0;
+			out_datums[i] = DummyDatum;
 		}
 		else
 		{
@@ -748,7 +748,7 @@ hstore_avals(PG_FUNCTION_ARGS)
 	{
 		if (HSTORE_VALISNULL(entries, i))
 		{
-			d[i] = (Datum) 0;
+			d[i] = DummyDatum;
 			nulls[i] = true;
 		}
 		else
@@ -799,7 +799,7 @@ hstore_to_array_internal(HStore *hs, int ndims)
 
 		if (HSTORE_VALISNULL(entries, i))
 		{
-			out_datums[i * 2 + 1] = (Datum) 0;
+			out_datums[i * 2 + 1] = DummyDatum;
 			out_nulls[i * 2 + 1] = true;
 		}
 		else
@@ -1051,7 +1051,7 @@ hstore_each(PG_FUNCTION_ARGS)
 
 		if (HSTORE_VALISNULL(entries, i))
 		{
-			dvalues[1] = (Datum) 0;
+			dvalues[1] = DummyDatum;
 			nulls[1] = true;
 		}
 		else
diff --git a/contrib/intarray/_int_bool.c b/contrib/intarray/_int_bool.c
index 2b2c3f4029e..0ee6ea7d5c5 100644
--- a/contrib/intarray/_int_bool.c
+++ b/contrib/intarray/_int_bool.c
@@ -499,12 +499,12 @@ bqarr_in(PG_FUNCTION_ARGS)
 	if (makepol(&state) == ERR)
 		PG_RETURN_NULL();
 	if (!state.num)
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("empty query")));
 
 	if (state.num > QUERYTYPEMAXITEMS)
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
 				 errmsg("number of query items (%d) exceeds the maximum allowed (%d)",
 						state.num, (int) QUERYTYPEMAXITEMS)));
diff --git a/contrib/ltree/_ltree_gist.c b/contrib/ltree/_ltree_gist.c
index 286ad24fbe8..2d71cea7e5a 100644
--- a/contrib/ltree/_ltree_gist.c
+++ b/contrib/ltree/_ltree_gist.c
@@ -84,7 +84,7 @@ _ltree_compress(PG_FUNCTION_ARGS)
 					  entry->rel, entry->page,
 					  entry->offset, false);
 	}
-	else if (!LTG_ISALLTRUE(entry->key))
+	else if (!LTG_ISALLTRUE(entry->key.value))
 	{
 		int32		i;
 		ltree_gist *key;
diff --git a/contrib/ltree/ltree_gist.c b/contrib/ltree/ltree_gist.c
index 932f69bff2d..49bf8e32593 100644
--- a/contrib/ltree/ltree_gist.c
+++ b/contrib/ltree/ltree_gist.c
@@ -115,7 +115,7 @@ ltree_decompress(PG_FUNCTION_ARGS)
 	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
 	ltree_gist *key = (ltree_gist *) PG_DETOAST_DATUM(entry->key);
 
-	if (PointerGetDatum(key) != entry->key)
+	if (PointerGetDatum(key).value != entry->key.value)
 	{
 		GISTENTRY  *retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
 
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 990c965aa92..458e8bcf3ff 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -336,7 +336,7 @@ brin_page_items(PG_FUNCTION_ARGS)
 	brin_free_desc(bdesc);
 	index_close(indexRel, AccessShareLock);
 
-	return (Datum) 0;
+	PG_RETURN_DUMMY();
 }
 
 Datum
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index 1b299374890..2396101342a 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -187,7 +187,7 @@ gist_page_items_bytea(PG_FUNCTION_ARGS)
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
 
-	return (Datum) 0;
+	PG_RETURN_DUMMY();
 }
 
 Datum
@@ -353,7 +353,7 @@ gist_page_items(PG_FUNCTION_ARGS)
 		}
 		else
 		{
-			values[4] = (Datum) 0;
+			//values[4] = DummyDatum;
 			nulls[4] = true;
 		}
 
@@ -362,5 +362,5 @@ gist_page_items(PG_FUNCTION_ARGS)
 
 	relation_close(indexRel, AccessShareLock);
 
-	return (Datum) 0;
+	PG_RETURN_DUMMY();
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index ae0291e6e96..6450f122b72 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -640,7 +640,7 @@ pg_buffercache_usage_counts(PG_FUNCTION_ARGS)
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
 
-	return (Datum) 0;
+	PG_RETURN_DUMMY();
 }
 
 /*
diff --git a/contrib/pg_prewarm/autoprewarm.c b/contrib/pg_prewarm/autoprewarm.c
index c01b9c7e6a4..2f611a0971c 100644
--- a/contrib/pg_prewarm/autoprewarm.c
+++ b/contrib/pg_prewarm/autoprewarm.c
@@ -187,7 +187,7 @@ autoprewarm_main(Datum main_arg)
 	 * are detached before calling the on_shmem_exit callbacks, so we must put
 	 * apw_detach_shmem in the before_shmem_exit callback list.
 	 */
-	before_shmem_exit(apw_detach_shmem, 0);
+	before_shmem_exit(apw_detach_shmem, DummyDatum);
 
 	/*
 	 * Store our PID in the shared memory area --- unless there's already
@@ -850,11 +850,11 @@ autoprewarm_dump_now(PG_FUNCTION_ARGS)
 
 	apw_init_shmem();
 
-	PG_ENSURE_ERROR_CLEANUP(apw_detach_shmem, 0);
+	PG_ENSURE_ERROR_CLEANUP(apw_detach_shmem, DummyDatum);
 	{
 		num_blocks = apw_dump_now(false, true);
 	}
-	PG_END_ENSURE_ERROR_CLEANUP(apw_detach_shmem, 0);
+	PG_END_ENSURE_ERROR_CLEANUP(apw_detach_shmem, DummyDatum);
 
 	PG_RETURN_INT64((int64) num_blocks);
 }
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 9fc9635d330..1fe8807319c 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -570,7 +570,7 @@ pgss_shmem_startup(void)
 	 * exit hook to dump the statistics to disk.
 	 */
 	if (!IsUnderPostmaster)
-		on_shmem_exit(pgss_shmem_shutdown, (Datum) 0);
+		on_shmem_exit(pgss_shmem_shutdown, DummyDatum);
 
 	/*
 	 * Done if some other process already completed our initialization.
@@ -1598,7 +1598,7 @@ pg_stat_statements_1_13(PG_FUNCTION_ARGS)
 
 	pg_stat_statements_internal(fcinfo, PGSS_V1_13, showtext);
 
-	return (Datum) 0;
+	PG_RETURN_DUMMY();
 }
 
 Datum
@@ -1608,7 +1608,7 @@ pg_stat_statements_1_12(PG_FUNCTION_ARGS)
 
 	pg_stat_statements_internal(fcinfo, PGSS_V1_12, showtext);
 
-	return (Datum) 0;
+	PG_RETURN_DUMMY();
 }
 
 Datum
@@ -1618,7 +1618,7 @@ pg_stat_statements_1_11(PG_FUNCTION_ARGS)
 
 	pg_stat_statements_internal(fcinfo, PGSS_V1_11, showtext);
 
-	return (Datum) 0;
+	PG_RETURN_DUMMY();
 }
 
 Datum
@@ -1628,7 +1628,7 @@ pg_stat_statements_1_10(PG_FUNCTION_ARGS)
 
 	pg_stat_statements_internal(fcinfo, PGSS_V1_10, showtext);
 
-	return (Datum) 0;
+	PG_RETURN_DUMMY();
 }
 
 Datum
@@ -1638,7 +1638,7 @@ pg_stat_statements_1_9(PG_FUNCTION_ARGS)
 
 	pg_stat_statements_internal(fcinfo, PGSS_V1_9, showtext);
 
-	return (Datum) 0;
+	PG_RETURN_DUMMY();
 }
 
 Datum
@@ -1648,7 +1648,7 @@ pg_stat_statements_1_8(PG_FUNCTION_ARGS)
 
 	pg_stat_statements_internal(fcinfo, PGSS_V1_8, showtext);
 
-	return (Datum) 0;
+	PG_RETURN_DUMMY();
 }
 
 Datum
@@ -1658,7 +1658,7 @@ pg_stat_statements_1_3(PG_FUNCTION_ARGS)
 
 	pg_stat_statements_internal(fcinfo, PGSS_V1_3, showtext);
 
-	return (Datum) 0;
+	PG_RETURN_DUMMY();
 }
 
 Datum
@@ -1668,7 +1668,7 @@ pg_stat_statements_1_2(PG_FUNCTION_ARGS)
 
 	pg_stat_statements_internal(fcinfo, PGSS_V1_2, showtext);
 
-	return (Datum) 0;
+	PG_RETURN_DUMMY();
 }
 
 /*
@@ -1681,7 +1681,7 @@ pg_stat_statements(PG_FUNCTION_ARGS)
 	/* If it's really API 1.1, we'll figure that out below */
 	pg_stat_statements_internal(fcinfo, PGSS_V1_0, true);
 
-	return (Datum) 0;
+	PG_RETURN_DUMMY();
 }
 
 /* Common code for all versions of pg_stat_statements() */
diff --git a/contrib/pgrowlocks/pgrowlocks.c b/contrib/pgrowlocks/pgrowlocks.c
index f88269332b6..e11d9c610a6 100644
--- a/contrib/pgrowlocks/pgrowlocks.c
+++ b/contrib/pgrowlocks/pgrowlocks.c
@@ -275,5 +275,5 @@ pgrowlocks(PG_FUNCTION_ARGS)
 
 	table_endscan(scan);
 	table_close(rel, AccessShareLock);
-	return (Datum) 0;
+	PG_RETURN_DUMMY();
 }
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 0d9c2b0b653..267cc2ce7ae 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -306,7 +306,7 @@ pgstat_relation(Relation rel, FunctionCallInfo fcinfo)
 				 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
 	}
 
-	return 0;					/* should not happen */
+	return DummyDatum;					/* should not happen */
 }
 
 /*
diff --git a/contrib/postgres_fdw/connection.c b/contrib/postgres_fdw/connection.c
index e8148f2c5a2..06ef45a0958 100644
--- a/contrib/postgres_fdw/connection.c
+++ b/contrib/postgres_fdw/connection.c
@@ -232,9 +232,9 @@ GetConnection(UserMapping *user, bool will_prep_stmt, PgFdwConnState **state)
 		RegisterXactCallback(pgfdw_xact_callback, NULL);
 		RegisterSubXactCallback(pgfdw_subxact_callback, NULL);
 		CacheRegisterSyscacheCallback(FOREIGNSERVEROID,
-									  pgfdw_inval_callback, (Datum) 0);
+									  pgfdw_inval_callback, DummyDatum);
 		CacheRegisterSyscacheCallback(USERMAPPINGOID,
-									  pgfdw_inval_callback, (Datum) 0);
+									  pgfdw_inval_callback, DummyDatum);
 	}
 
 	/* Set flag that we did GetConnection during the current transaction */
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 456b267f70b..d517a60a206 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -4743,7 +4743,7 @@ apply_returning_filter(PgFdwDirectModifyState *dmstate,
 
 		if (j == 0)
 		{
-			values[i] = (Datum) 0;
+			//values[i] = DummyDatum;
 			isnull[i] = true;
 		}
 		else
diff --git a/contrib/postgres_fdw/shippable.c b/contrib/postgres_fdw/shippable.c
index da3b13b207d..dbe3ac3a32d 100644
--- a/contrib/postgres_fdw/shippable.c
+++ b/contrib/postgres_fdw/shippable.c
@@ -101,7 +101,7 @@ InitializeShippableCache(void)
 	/* Set up invalidation callback on pg_foreign_server. */
 	CacheRegisterSyscacheCallback(FOREIGNSERVEROID,
 								  InvalidateShippableCacheCallback,
-								  (Datum) 0);
+								  DummyDatum);
 }
 
 /*
diff --git a/contrib/seg/seg.c b/contrib/seg/seg.c
index b5de2a5e1be..74e65fcbcf6 100644
--- a/contrib/seg/seg.c
+++ b/contrib/seg/seg.c
@@ -230,7 +230,7 @@ gseg_union(PG_FUNCTION_ARGS)
 	int		   *sizep = (int *) PG_GETARG_POINTER(1);
 	int			numranges,
 				i;
-	Datum		out = 0;
+	Datum		out = DummyDatum;
 	Datum		tmp;
 
 #ifdef GIST_DEBUG
diff --git a/contrib/sepgsql/label.c b/contrib/sepgsql/label.c
index 996ce174454..5d57563ecb7 100644
--- a/contrib/sepgsql/label.c
+++ b/contrib/sepgsql/label.c
@@ -330,7 +330,7 @@ sepgsql_fmgr_hook(FmgrHookEventType event,
 				stack = palloc(sizeof(*stack));
 				stack->old_label = NULL;
 				stack->new_label = sepgsql_avc_trusted_proc(flinfo->fn_oid);
-				stack->next_private = 0;
+				stack->next_private.value = 0;
 
 				MemoryContextSwitchTo(oldcxt);
 
diff --git a/contrib/sepgsql/uavc.c b/contrib/sepgsql/uavc.c
index d9ccbc38bc5..02472e3bdfe 100644
--- a/contrib/sepgsql/uavc.c
+++ b/contrib/sepgsql/uavc.c
@@ -517,5 +517,5 @@ sepgsql_avc_init(void)
 				(errmsg("SELinux: kernel status page uses fallback mode")));
 
 	/* Arrange to close selinux status page on process exit. */
-	on_proc_exit(sepgsql_avc_exit, 0);
+	on_proc_exit(sepgsql_avc_exit, DummyDatum);
 }
diff --git a/contrib/spi/moddatetime.c b/contrib/spi/moddatetime.c
index 5013eee433e..511402d26e8 100644
--- a/contrib/spi/moddatetime.c
+++ b/contrib/spi/moddatetime.c
@@ -118,7 +118,7 @@ moddatetime(PG_FUNCTION_ARGS)
 				(errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
 				 errmsg("attribute \"%s\" of \"%s\" must be type TIMESTAMP or TIMESTAMPTZ",
 						args[0], relname)));
-		newdt = (Datum) 0;		/* keep compiler quiet */
+		newdt = DummyDatum;		/* keep compiler quiet */
 	}
 	newdtnull = false;
 
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index da702011193..483327694ba 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -211,7 +211,7 @@ X509_NAME_field_to_text(X509_NAME *name, text *fieldName)
 	pfree(string_fieldname);
 	index = X509_NAME_get_index_by_NID(name, nid, -1);
 	if (index < 0)
-		return (Datum) 0;
+		return DummyDatum;
 	data = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, index));
 	return ASN1_STRING_to_text(data);
 }
@@ -245,7 +245,7 @@ ssl_client_dn_field(PG_FUNCTION_ARGS)
 
 	result = X509_NAME_field_to_text(X509_get_subject_name(MyProcPort->peer), fieldname);
 
-	if (!result)
+	if (!result.value) // XXX
 		PG_RETURN_NULL();
 	else
 		return result;
@@ -280,7 +280,7 @@ ssl_issuer_field(PG_FUNCTION_ARGS)
 
 	result = X509_NAME_field_to_text(X509_get_issuer_name(MyProcPort->peer), fieldname);
 
-	if (!result)
+	if (!result.value) // XXX
 		PG_RETURN_NULL();
 	else
 		return result;
diff --git a/contrib/tablefunc/tablefunc.c b/contrib/tablefunc/tablefunc.c
index 74afdc0977f..950a3bcd573 100644
--- a/contrib/tablefunc/tablefunc.c
+++ b/contrib/tablefunc/tablefunc.c
@@ -593,7 +593,7 @@ crosstab(PG_FUNCTION_ARGS)
 	/* release SPI related resources (and return to caller's context) */
 	SPI_finish();
 
-	return (Datum) 0;
+	PG_RETURN_DUMMY();
 }
 
 /*
@@ -695,7 +695,7 @@ crosstab_hash(PG_FUNCTION_ARGS)
 	rsinfo->setDesc = tupdesc;
 	MemoryContextSwitchTo(oldcontext);
 
-	return (Datum) 0;
+	PG_RETURN_DUMMY();
 }
 
 /*
@@ -1047,7 +1047,7 @@ connectby_text(PG_FUNCTION_ARGS)
 	 * to build our tuples with, so the caller can verify we did what it was
 	 * expecting.
 	 */
-	return (Datum) 0;
+	PG_RETURN_DUMMY();
 }
 
 PG_FUNCTION_INFO_V1(connectby_text_serial);
@@ -1126,7 +1126,7 @@ connectby_text_serial(PG_FUNCTION_ARGS)
 	 * to build our tuples with, so the caller can verify we did what it was
 	 * expecting.
 	 */
-	return (Datum) 0;
+	PG_RETURN_DUMMY();
 }
 
 
diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c
index 4ac291c8251..9f5a813b77a 100644
--- a/contrib/xml2/xpath.c
+++ b/contrib/xml2/xpath.c
@@ -883,5 +883,5 @@ xpath_table(PG_FUNCTION_ARGS)
 	 * to build our tuples with, so the caller can verify we did what it was
 	 * expecting.
 	 */
-	return (Datum) 0;
+	PG_RETURN_DUMMY();  // XXX?
 }
diff --git a/src/backend/access/brin/brin_bloom.c b/src/backend/access/brin/brin_bloom.c
index 7c3f7d454fc..041b262cf3e 100644
--- a/src/backend/access/brin/brin_bloom.c
+++ b/src/backend/access/brin/brin_bloom.c
@@ -693,14 +693,14 @@ brin_bloom_union(PG_FUNCTION_ARGS)
 	filter_a->nbits_set = pg_popcount((const char *) filter_a->data, nbytes);
 
 	/* if we decompressed filter_a, update the summary */
-	if (PointerGetDatum(filter_a) != col_a->bv_values[0])
+	if (PointerGetDatum(filter_a).value != col_a->bv_values[0].value)
 	{
 		pfree(DatumGetPointer(col_a->bv_values[0]));
 		col_a->bv_values[0] = PointerGetDatum(filter_a);
 	}
 
 	/* also free filter_b, if it was decompressed */
-	if (PointerGetDatum(filter_b) != col_b->bv_values[0])
+	if (PointerGetDatum(filter_b).value != col_b->bv_values[0].value)
 		pfree(filter_b);
 
 	PG_RETURN_VOID();
diff --git a/src/backend/access/brin/brin_inclusion.c b/src/backend/access/brin/brin_inclusion.c
index b86ca5744a3..882b1c4cdda 100644
--- a/src/backend/access/brin/brin_inclusion.c
+++ b/src/backend/access/brin/brin_inclusion.c
@@ -229,7 +229,7 @@ brin_inclusion_add_value(PG_FUNCTION_ARGS)
 	{
 		pfree(DatumGetPointer(column->bv_values[INCLUSION_UNION]));
 
-		if (result == newval)
+		if (result.value == newval.value)
 			result = datumCopy(result, attr->attbyval, attr->attlen);
 	}
 	column->bv_values[INCLUSION_UNION] = result;
@@ -525,7 +525,7 @@ brin_inclusion_union(PG_FUNCTION_ARGS)
 	{
 		pfree(DatumGetPointer(col_a->bv_values[INCLUSION_UNION]));
 
-		if (result == col_b->bv_values[INCLUSION_UNION])
+		if (result.value == col_b->bv_values[INCLUSION_UNION].value)
 			result = datumCopy(result, attr->attbyval, attr->attlen);
 	}
 	col_a->bv_values[INCLUSION_UNION] = result;
diff --git a/src/backend/access/brin/brin_minmax.c b/src/backend/access/brin/brin_minmax.c
index 79c5a0aa185..52132aa4113 100644
--- a/src/backend/access/brin/brin_minmax.c
+++ b/src/backend/access/brin/brin_minmax.c
@@ -193,7 +193,7 @@ brin_minmax_consistent(PG_FUNCTION_ARGS)
 		default:
 			/* shouldn't happen */
 			elog(ERROR, "invalid strategy number %d", key->sk_strategy);
-			matches = 0;
+			matches = DummyDatum;
 			break;
 	}
 
diff --git a/src/backend/access/brin/brin_minmax_multi.c b/src/backend/access/brin/brin_minmax_multi.c
index e323c0447d0..4e305e469f3 100644
--- a/src/backend/access/brin/brin_minmax_multi.c
+++ b/src/backend/access/brin/brin_minmax_multi.c
@@ -799,7 +799,7 @@ brin_range_deserialize(int maxvalues, SerializedRanges *serialized)
 	{
 		if (typbyval)			/* simple by-value data types */
 		{
-			Datum		v = 0;
+			Datum		v;
 
 			memcpy(&v, ptr, typlen);
 
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 1173a6d81b5..15c828b67b9 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -759,7 +759,7 @@ heap_getsysattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
 			break;
 		default:
 			elog(ERROR, "invalid attnum: %d", attnum);
-			result = 0;			/* keep compiler quiet */
+			result = DummyDatum;			/* keep compiler quiet */
 			break;
 	}
 	return result;
@@ -1041,7 +1041,7 @@ expand_tuple(HeapTuple *targetHeapTuple,
 					 &bitMask,
 					 &targetData,
 					 infoMask,
-					 (Datum) 0,
+					 DummyDatum,
 					 true);
 		}
 	}							/* end loop over missing attributes */
@@ -1375,7 +1375,7 @@ heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc,
 
 		if (hasnulls && att_isnull(attnum, bp))
 		{
-			values[attnum] = (Datum) 0;
+			values[attnum] = DummyDatum;
 			isnull[attnum] = true;
 			slow = true;		/* can't use attcacheoff anymore */
 			continue;
diff --git a/src/backend/access/common/indextuple.c b/src/backend/access/common/indextuple.c
index 1986b943a28..11fa2332d09 100644
--- a/src/backend/access/common/indextuple.c
+++ b/src/backend/access/common/indextuple.c
@@ -494,7 +494,7 @@ index_deform_tuple_internal(TupleDesc tupleDescriptor,
 
 		if (hasnulls && att_isnull(attnum, bp))
 		{
-			values[attnum] = (Datum) 0;
+			//values[attnum] = DummyDatum;
 			isnull[attnum] = true;
 			slow = true;		/* can't use attcacheoff anymore */
 			continue;
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 594a657ea1a..f7811bd2593 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -1337,7 +1337,7 @@ transformRelOptions(Datum oldOptions, List *defList, const char *namspace,
 	if (astate)
 		result = makeArrayResult(astate, CurrentMemoryContext);
 	else
-		result = (Datum) 0;
+		result = DummyDatum;
 
 	return result;
 }
@@ -1575,7 +1575,7 @@ parseLocalRelOptions(local_relopts *relopts, Datum options, bool validate)
 		i++;
 	}
 
-	if (options != (Datum) 0)
+	if (options.value != DummyDatum.value)
 		parseRelOptionsInternal(options, validate, values, nopts);
 
 	return values;
@@ -2019,7 +2019,7 @@ build_local_reloptions(local_relopts *relopts, Datum options, bool validate)
 bytea *
 partitioned_table_reloptions(Datum reloptions, bool validate)
 {
-	if (validate && reloptions)
+	if (validate && reloptions.value)
 		ereport(ERROR,
 				errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				errmsg("cannot specify storage parameters for a partitioned table"),
diff --git a/src/backend/access/common/tupconvert.c b/src/backend/access/common/tupconvert.c
index 54dc2f4ab80..7234a5a902a 100644
--- a/src/backend/access/common/tupconvert.c
+++ b/src/backend/access/common/tupconvert.c
@@ -85,7 +85,7 @@ convert_tuples_by_position(TupleDesc indesc,
 	n = indesc->natts + 1;		/* +1 for NULL */
 	map->invalues = (Datum *) palloc(n * sizeof(Datum));
 	map->inisnull = (bool *) palloc(n * sizeof(bool));
-	map->invalues[0] = (Datum) 0;	/* set up the NULL entry */
+	map->invalues[0] = DummyDatum;	/* set up the NULL entry */
 	map->inisnull[0] = true;
 
 	return map;
@@ -141,7 +141,7 @@ convert_tuples_by_name_attrmap(TupleDesc indesc,
 	n = indesc->natts + 1;		/* +1 for NULL */
 	map->invalues = (Datum *) palloc(n * sizeof(Datum));
 	map->inisnull = (bool *) palloc(n * sizeof(bool));
-	map->invalues[0] = (Datum) 0;	/* set up the NULL entry */
+	map->invalues[0] = DummyDatum;	/* set up the NULL entry */
 	map->inisnull[0] = true;
 
 	return map;
@@ -226,7 +226,7 @@ execute_attr_map_slot(AttrMap *attrMap,
 		/* attrMap->attnums[i] == 0 means it's a NULL datum. */
 		if (j == -1)
 		{
-			outvalues[i] = (Datum) 0;
+			//outvalues[i] = DummyDatum;
 			outisnull[i] = true;
 		}
 		else
diff --git a/src/backend/access/gin/gininsert.c b/src/backend/access/gin/gininsert.c
index 47b1898a064..df6989231ab 100644
--- a/src/backend/access/gin/gininsert.c
+++ b/src/backend/access/gin/gininsert.c
@@ -1436,7 +1436,7 @@ GinBufferStoreTuple(GinBuffer *buffer, GinTuple *tup)
 		if (tup->category == GIN_CAT_NORM_KEY)
 			buffer->key = datumCopy(key, buffer->typbyval, buffer->typlen);
 		else
-			buffer->key = (Datum) 0;
+			buffer->key = DummyDatum;
 	}
 
 	/*
@@ -1534,7 +1534,7 @@ GinBufferReset(GinBuffer *buffer)
 	 * Not required, but makes it more likely to trigger NULL dereference if
 	 * using the value incorrectly, etc.
 	 */
-	buffer->key = (Datum) 0;
+	buffer->key = DummyDatum;
 
 	buffer->attnum = 0;
 	buffer->category = 0;
@@ -2351,7 +2351,7 @@ _gin_parse_tuple_key(GinTuple *a)
 	Datum		key;
 
 	if (a->category != GIN_CAT_NORM_KEY)
-		return (Datum) 0;
+		return DummyDatum;
 
 	if (a->typbyval)
 	{
diff --git a/src/backend/access/gin/ginscan.c b/src/backend/access/gin/ginscan.c
index c2d1771bd77..d32cf8fe2ee 100644
--- a/src/backend/access/gin/ginscan.c
+++ b/src/backend/access/gin/ginscan.c
@@ -148,7 +148,7 @@ ginScanKeyAddHiddenEntry(GinScanOpaque so, GinScanKey key,
 	/* strategy is of no interest because this is not a partial-match item */
 	key->scanEntry[i] = ginFillScanEntry(so, key->attnum,
 										 InvalidStrategy, key->searchMode,
-										 (Datum) 0, queryCategory,
+										 DummyDatum, queryCategory,
 										 false, NULL);
 }
 
@@ -417,7 +417,7 @@ ginNewScanKey(IndexScanDesc scan)
 		hasNullQuery = true;
 		ginFillScanKey(so, FirstOffsetNumber,
 					   InvalidStrategy, GIN_SEARCH_MODE_EVERYTHING,
-					   (Datum) 0, 0,
+					   DummyDatum, 0,
 					   NULL, NULL, NULL, NULL);
 	}
 
diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c
index 78f7b7a2495..c0102eae915 100644
--- a/src/backend/access/gin/ginutil.c
+++ b/src/backend/access/gin/ginutil.c
@@ -501,7 +501,7 @@ ginExtractEntries(GinState *ginstate, OffsetNumber attnum,
 	{
 		*nentries = 1;
 		entries = (Datum *) palloc(sizeof(Datum));
-		entries[0] = (Datum) 0;
+		entries[0] = DummyDatum;
 		*categories = (GinNullCategory *) palloc(sizeof(GinNullCategory));
 		(*categories)[0] = GIN_CAT_NULL_ITEM;
 		return entries;
@@ -523,7 +523,7 @@ ginExtractEntries(GinState *ginstate, OffsetNumber attnum,
 	{
 		*nentries = 1;
 		entries = (Datum *) palloc(sizeof(Datum));
-		entries[0] = (Datum) 0;
+		entries[0] = DummyDatum;
 		*categories = (GinNullCategory *) palloc(sizeof(GinNullCategory));
 		(*categories)[0] = GIN_CAT_EMPTY_ITEM;
 		return entries;
diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c
index 392163cb229..ba3479c8661 100644
--- a/src/backend/access/gist/gistproc.c
+++ b/src/backend/access/gist/gistproc.c
@@ -1396,7 +1396,8 @@ gist_point_consistent(PG_FUNCTION_ARGS)
 														  PointerGetDatum(entry),
 														  PolygonPGetDatum(query),
 														  Int16GetDatum(RTOverlapStrategyNumber),
-														  0, PointerGetDatum(recheck)));
+														  DummyDatum,
+														  PointerGetDatum(recheck)));
 
 				if (GIST_LEAF(entry) && result)
 				{
@@ -1423,7 +1424,8 @@ gist_point_consistent(PG_FUNCTION_ARGS)
 														  PointerGetDatum(entry),
 														  CirclePGetDatum(query),
 														  Int16GetDatum(RTOverlapStrategyNumber),
-														  0, PointerGetDatum(recheck)));
+														  DummyDatum,
+														  PointerGetDatum(recheck)));
 
 				if (GIST_LEAF(entry) && result)
 				{
@@ -1719,9 +1721,9 @@ gist_bbox_zorder_abbrev_convert(Datum original, SortSupport ssup)
 	z = point_zorder_internal(p->x, p->y);
 
 #if SIZEOF_DATUM == 8
-	return (Datum) z;
+	return UInt64GetDatum(z);
 #else
-	return (Datum) (z >> 32);
+	return (Datum) (z >> 32); // FIXME
 #endif
 }
 
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index c0aa7d0222f..5f13682e6f6 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -188,7 +188,7 @@ gistMakeUnionItVec(GISTSTATE *giststate, IndexTuple *itvec, int len,
 		/* If this column was all NULLs, the union is NULL */
 		if (evec->n == 0)
 		{
-			attr[i] = (Datum) 0;
+			attr[i] = DummyDatum;
 			isnull[i] = true;
 		}
 		else
@@ -249,7 +249,7 @@ gistMakeUnionKey(GISTSTATE *giststate, int attno,
 	if (isnull1 && isnull2)
 	{
 		*dstisnull = true;
-		*dst = (Datum) 0;
+		*dst = DummyDatum;
 	}
 	else
 	{
@@ -568,7 +568,7 @@ gistdentryinit(GISTSTATE *giststate, int nkey, GISTENTRY *e,
 						  dep->leafkey);
 	}
 	else
-		gistentryinit(*e, (Datum) 0, r, pg, o, l);
+		gistentryinit(*e, DummyDatum, r, pg, o, l);
 }
 
 IndexTuple
@@ -604,7 +604,7 @@ gistCompressValues(GISTSTATE *giststate, Relation r,
 	for (i = 0; i < IndexRelationGetNumberOfKeyAttributes(r); i++)
 	{
 		if (isnull[i])
-			compatt[i] = (Datum) 0;
+			compatt[i] = DummyDatum;
 		else
 		{
 			GISTENTRY	centry;
@@ -632,7 +632,7 @@ gistCompressValues(GISTSTATE *giststate, Relation r,
 		for (; i < r->rd_att->natts; i++)
 		{
 			if (isnull[i])
-				compatt[i] = (Datum) 0;
+				compatt[i] = DummyDatum;
 			else
 				compatt[i] = attdata[i];
 		}
@@ -682,7 +682,7 @@ gistFetchTuple(GISTSTATE *giststate, Relation r, IndexTuple tuple)
 			if (!isnull[i])
 				fetchatt[i] = gistFetchAtt(giststate, i, datum, r);
 			else
-				fetchatt[i] = (Datum) 0;
+				fetchatt[i] = DummyDatum;
 		}
 		else if (giststate->compressFn[i].fn_oid == InvalidOid)
 		{
@@ -693,7 +693,7 @@ gistFetchTuple(GISTSTATE *giststate, Relation r, IndexTuple tuple)
 			if (!isnull[i])
 				fetchatt[i] = datum;
 			else
-				fetchatt[i] = (Datum) 0;
+				fetchatt[i] = DummyDatum;
 		}
 		else
 		{
@@ -703,7 +703,7 @@ gistFetchTuple(GISTSTATE *giststate, Relation r, IndexTuple tuple)
 			 * in this column, and we can replace it with a NULL.
 			 */
 			isnull[i] = true;
-			fetchatt[i] = (Datum) 0;
+			fetchatt[i] = DummyDatum;
 		}
 	}
 
diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c
index 219df1971da..c6ade655c03 100644
--- a/src/backend/access/index/indexam.c
+++ b/src/backend/access/index/indexam.c
@@ -998,7 +998,7 @@ index_store_float8_orderby_distances(IndexScanDesc scan, Oid *orderByTypes,
 			}
 			else
 			{
-				scan->xs_orderbyvals[i] = (Datum) 0;
+				scan->xs_orderbyvals[i] = DummyDatum;
 				scan->xs_orderbynulls[i] = true;
 			}
 		}
@@ -1012,7 +1012,7 @@ index_store_float8_orderby_distances(IndexScanDesc scan, Oid *orderByTypes,
 			}
 			else
 			{
-				scan->xs_orderbyvals[i] = (Datum) 0;
+				scan->xs_orderbyvals[i] = DummyDatum;
 				scan->xs_orderbynulls[i] = true;
 			}
 		}
diff --git a/src/backend/access/nbtree/nbtcompare.c b/src/backend/access/nbtree/nbtcompare.c
index e1b52acd20d..8723093e752 100644
--- a/src/backend/access/nbtree/nbtcompare.c
+++ b/src/backend/access/nbtree/nbtcompare.c
@@ -88,7 +88,7 @@ bool_decrement(Relation rel, Datum existing, bool *underflow)
 	{
 		/* return value is undefined */
 		*underflow = true;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 
 	*underflow = false;
@@ -104,7 +104,7 @@ bool_increment(Relation rel, Datum existing, bool *overflow)
 	{
 		/* return value is undefined */
 		*overflow = true;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 
 	*overflow = false;
@@ -160,7 +160,7 @@ int2_decrement(Relation rel, Datum existing, bool *underflow)
 	{
 		/* return value is undefined */
 		*underflow = true;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 
 	*underflow = false;
@@ -176,7 +176,7 @@ int2_increment(Relation rel, Datum existing, bool *overflow)
 	{
 		/* return value is undefined */
 		*overflow = true;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 
 	*overflow = false;
@@ -228,7 +228,7 @@ int4_decrement(Relation rel, Datum existing, bool *underflow)
 	{
 		/* return value is undefined */
 		*underflow = true;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 
 	*underflow = false;
@@ -244,7 +244,7 @@ int4_increment(Relation rel, Datum existing, bool *overflow)
 	{
 		/* return value is undefined */
 		*overflow = true;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 
 	*overflow = false;
@@ -316,7 +316,7 @@ int8_decrement(Relation rel, Datum existing, bool *underflow)
 	{
 		/* return value is undefined */
 		*underflow = true;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 
 	*underflow = false;
@@ -332,7 +332,7 @@ int8_increment(Relation rel, Datum existing, bool *overflow)
 	{
 		/* return value is undefined */
 		*overflow = true;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 
 	*overflow = false;
@@ -482,7 +482,7 @@ oid_decrement(Relation rel, Datum existing, bool *underflow)
 	{
 		/* return value is undefined */
 		*underflow = true;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 
 	*underflow = false;
@@ -498,7 +498,7 @@ oid_increment(Relation rel, Datum existing, bool *overflow)
 	{
 		/* return value is undefined */
 		*overflow = true;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 
 	*overflow = false;
@@ -561,7 +561,7 @@ char_decrement(Relation rel, Datum existing, bool *underflow)
 	{
 		/* return value is undefined */
 		*underflow = true;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 
 	*underflow = false;
@@ -577,7 +577,7 @@ char_increment(Relation rel, Datum existing, bool *overflow)
 	{
 		/* return value is undefined */
 		*overflow = true;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 
 	*overflow = false;
diff --git a/src/backend/access/nbtree/nbtpreprocesskeys.c b/src/backend/access/nbtree/nbtpreprocesskeys.c
index 21c519cd108..cceadede0f9 100644
--- a/src/backend/access/nbtree/nbtpreprocesskeys.c
+++ b/src/backend/access/nbtree/nbtpreprocesskeys.c
@@ -1942,7 +1942,7 @@ _bt_preprocess_array_keys(IndexScanDesc scan, int *new_numberOfKeys)
 								   InvalidOid,	/* opclass input subtype */
 								   collation,	/* index column's collation */
 								   cmp_proc,	/* equality operator's proc */
-								   (Datum) 0);	/* constant */
+								   DummyDatum);	/* constant */
 
 			/* Initialize generic BTArrayKeyInfo fields */
 			so->arrayKeys[numArrayKeys].scan_key = numArrayKeyData;
diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c
index fdff960c130..e68e361c07a 100644
--- a/src/backend/access/nbtree/nbtree.c
+++ b/src/backend/access/nbtree/nbtree.c
@@ -608,7 +608,7 @@ btestimateparallelscan(Relation rel, int nkeys, int norderbys)
 	 * Pessimistically assume that all attributes prior to the least
 	 * significant attribute require a skip array (and an associated key)
 	 */
-	genericattrspace = datumEstimateSpace((Datum) 0, false, true,
+	genericattrspace = datumEstimateSpace(DummyDatum, false, true,
 										  sizeof(Datum));
 	for (int attnum = 1; attnum < nkeyatts; attnum++)
 	{
@@ -627,7 +627,7 @@ btestimateparallelscan(Relation rel, int nkeys, int norderbys)
 		if (attr->attbyval)
 		{
 			/* This index attribute stores pass-by-value datums */
-			Size		estfixed = datumEstimateSpace((Datum) 0, false,
+			Size		estfixed = datumEstimateSpace(DummyDatum, false,
 													  true, attr->attlen);
 
 			estnbtreeshared = add_size(estnbtreeshared, estfixed);
@@ -688,7 +688,7 @@ _bt_parallel_serialize_arrays(Relation rel, BTParallelScanDesc btscan,
 		if (skey->sk_flags & (SK_BT_MINVAL | SK_BT_MAXVAL))
 		{
 			/* No sk_argument datum to serialize */
-			Assert(skey->sk_argument == 0);
+			Assert(skey->sk_argument.value == 0);
 			continue;
 		}
 
@@ -726,9 +726,9 @@ _bt_parallel_restore_arrays(Relation rel, BTParallelScanDesc btscan,
 		}
 
 		/* Restore skip array by restoring its key directly */
-		if (!array->attbyval && skey->sk_argument)
+		if (!array->attbyval && DatumGetPointer(skey->sk_argument))
 			pfree(DatumGetPointer(skey->sk_argument));
-		skey->sk_argument = (Datum) 0;
+		skey->sk_argument = DummyDatum;
 		memcpy(&skey->sk_flags, datumshared, sizeof(int));
 		datumshared += sizeof(int);
 
@@ -743,7 +743,7 @@ _bt_parallel_restore_arrays(Relation rel, BTParallelScanDesc btscan,
 		skey->sk_argument = datumRestore(&datumshared, &isnull);
 		if (isnull)
 		{
-			Assert(skey->sk_argument == 0);
+			Assert(skey->sk_argument.value == 0);
 			Assert(skey->sk_flags & SK_SEARCHNULL);
 			Assert(skey->sk_flags & SK_ISNULL);
 		}
diff --git a/src/backend/access/nbtree/nbtsearch.c b/src/backend/access/nbtree/nbtsearch.c
index d69798795b4..45f7ae720e2 100644
--- a/src/backend/access/nbtree/nbtsearch.c
+++ b/src/backend/access/nbtree/nbtsearch.c
@@ -1133,7 +1133,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
 										   InvalidOid,
 										   InvalidOid,
 										   InvalidOid,
-										   (Datum) 0);
+										   DummyDatum);
 				}
 
 				/*
diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c
index 9aed207995f..6c0ca1cdccf 100644
--- a/src/backend/access/nbtree/nbtutils.c
+++ b/src/backend/access/nbtree/nbtutils.c
@@ -132,7 +132,7 @@ _bt_mkscankey(Relation rel, IndexTuple itup)
 	for (i = 0; i < indnkeyatts; i++)
 	{
 		FmgrInfo   *procinfo;
-		Datum		arg;
+		Datum		arg = DummyDatum;
 		bool		null;
 		int			flags;
 
@@ -151,7 +151,7 @@ _bt_mkscankey(Relation rel, IndexTuple itup)
 			arg = index_getattr(itup, i + 1, itupdesc, &null);
 		else
 		{
-			arg = (Datum) 0;
+			//arg = DummyDatum;
 			null = true;
 		}
 		flags = (null ? SK_ISNULL : 0) | (indoption[i] << SK_BT_INDOPTION_SHIFT);
@@ -568,7 +568,7 @@ _bt_skiparray_set_element(Relation rel, ScanKey skey, BTArrayKeyInfo *array,
 	}
 
 	/* Free memory previously allocated for sk_argument if needed */
-	if (!array->attbyval && skey->sk_argument)
+	if (!array->attbyval && DatumGetPointer(skey->sk_argument))
 		pfree(DatumGetPointer(skey->sk_argument));
 
 	/* tupdatum becomes new sk_argument/new current element */
@@ -589,11 +589,11 @@ _bt_skiparray_set_isnull(Relation rel, ScanKey skey, BTArrayKeyInfo *array)
 	Assert(array->null_elem && !array->low_compare && !array->high_compare);
 
 	/* Free memory previously allocated for sk_argument if needed */
-	if (!array->attbyval && skey->sk_argument)
+	if (!array->attbyval && DatumGetPointer(skey->sk_argument))
 		pfree(DatumGetPointer(skey->sk_argument));
 
 	/* NULL becomes new sk_argument/new current element */
-	skey->sk_argument = (Datum) 0;
+	skey->sk_argument = DummyDatum;
 	skey->sk_flags &= ~(SK_BT_MINVAL | SK_BT_MAXVAL |
 						SK_BT_NEXT | SK_BT_PRIOR);
 	skey->sk_flags |= (SK_SEARCHNULL | SK_ISNULL);
@@ -664,11 +664,11 @@ _bt_array_set_low_or_high(Relation rel, ScanKey skey, BTArrayKeyInfo *array,
 	Assert(array->num_elems == -1);
 
 	/* Free memory previously allocated for sk_argument if needed */
-	if (!array->attbyval && skey->sk_argument)
+	if (!array->attbyval && DatumGetPointer(skey->sk_argument))
 		pfree(DatumGetPointer(skey->sk_argument));
 
 	/* Reset flags */
-	skey->sk_argument = (Datum) 0;
+	skey->sk_argument = DummyDatum;
 	skey->sk_flags &= ~(SK_SEARCHNULL | SK_ISNULL |
 						SK_BT_MINVAL | SK_BT_MAXVAL |
 						SK_BT_NEXT | SK_BT_PRIOR);
@@ -816,7 +816,7 @@ _bt_array_decrement(Relation rel, ScanKey skey, BTArrayKeyInfo *array)
 	}
 
 	/* Accept value returned by opclass decrement callback */
-	if (!array->attbyval && skey->sk_argument)
+	if (!array->attbyval && DatumGetPointer(skey->sk_argument))
 		pfree(DatumGetPointer(skey->sk_argument));
 	skey->sk_argument = dec_sk_argument;
 
@@ -949,7 +949,7 @@ _bt_array_increment(Relation rel, ScanKey skey, BTArrayKeyInfo *array)
 	}
 
 	/* Accept value returned by opclass increment callback */
-	if (!array->attbyval && skey->sk_argument)
+	if (!array->attbyval && DatumGetPointer(skey->sk_argument))
 		pfree(DatumGetPointer(skey->sk_argument));
 	skey->sk_argument = inc_sk_argument;
 
@@ -2094,7 +2094,7 @@ _bt_verify_keys_with_arraykeys(IndexScanDesc scan)
 			return false;
 
 		if (array->num_elems != -1 &&
-			cur->sk_argument != array->elem_values[array->cur_elem])
+			cur->sk_argument.value != array->elem_values[array->cur_elem].value)
 			return false;
 		if (cur->sk_flags & (SK_BT_REQFWD | SK_BT_REQBKWD))
 		{
diff --git a/src/backend/access/spgist/spgdoinsert.c b/src/backend/access/spgist/spgdoinsert.c
index af6b27b2135..837f3e0018c 100644
--- a/src/backend/access/spgist/spgdoinsert.c
+++ b/src/backend/access/spgist/spgdoinsert.c
@@ -755,7 +755,7 @@ doPickSplit(Relation index, SpGistState *state,
 			if (it->tupstate == SPGIST_LIVE)
 			{
 				in.datums[nToInsert] =
-					isNulls ? (Datum) 0 : SGLTDATUM(it, state);
+					isNulls ? DummyDatum : SGLTDATUM(it, state);
 				oldLeafs[nToInsert] = it;
 				nToInsert++;
 				toDelete[nToDelete] = i;
@@ -781,7 +781,7 @@ doPickSplit(Relation index, SpGistState *state,
 			if (it->tupstate == SPGIST_LIVE)
 			{
 				in.datums[nToInsert] =
-					isNulls ? (Datum) 0 : SGLTDATUM(it, state);
+					isNulls ? DummyDatum : SGLTDATUM(it, state);
 				oldLeafs[nToInsert] = it;
 				nToInsert++;
 				toDelete[nToDelete] = i;
@@ -814,7 +814,7 @@ doPickSplit(Relation index, SpGistState *state,
 	 * for the picksplit function.  So don't increment nToInsert yet.
 	 */
 	in.datums[in.nTuples] =
-		isNulls ? (Datum) 0 : SGLTDATUM(newLeafTuple, state);
+		isNulls ? DummyDatum : SGLTDATUM(newLeafTuple, state);
 	oldLeafs[in.nTuples] = newLeafTuple;
 	in.nTuples++;
 
@@ -880,7 +880,7 @@ doPickSplit(Relation index, SpGistState *state,
 			/*
 			 * Nulls tree can contain only null key values.
 			 */
-			leafDatums[spgKeyColumn] = (Datum) 0;
+			leafDatums[spgKeyColumn] = DummyDatum;
 			leafIsnulls[spgKeyColumn] = true;
 
 			newLeafs[i] = spgFormLeafTuple(state, &oldLeafs[i]->heapPtr,
@@ -926,7 +926,7 @@ doPickSplit(Relation index, SpGistState *state,
 	 */
 	for (i = 0; i < out.nNodes; i++)
 	{
-		Datum		label = (Datum) 0;
+		Datum		label = DummyDatum;
 		bool		labelisnull = (out.nodeLabels == NULL);
 
 		if (!labelisnull)
@@ -1749,7 +1749,7 @@ spgSplitNodeAction(Relation index, SpGistState *state,
 
 	for (i = 0; i < out->result.splitTuple.prefixNNodes; i++)
 	{
-		Datum		label = (Datum) 0;
+		Datum		label = DummyDatum;
 		bool		labelisnull;
 
 		labelisnull = (out->result.splitTuple.prefixNodeLabels == NULL);
@@ -1967,7 +1967,7 @@ spgdoinsert(Relation index, SpGistState *state,
 		}
 	}
 	else
-		leafDatums[spgKeyColumn] = (Datum) 0;
+		leafDatums[spgKeyColumn] = DummyDatum;
 
 	/* Likewise, ensure that any INCLUDE values are not toasted */
 	for (int i = spgFirstIncludeColumn; i < leafDescriptor->natts; i++)
@@ -1980,7 +1980,7 @@ spgdoinsert(Relation index, SpGistState *state,
 				leafDatums[i] = datums[i];
 		}
 		else
-			leafDatums[i] = (Datum) 0;
+			leafDatums[i] = DummyDatum;
 	}
 
 	/*
diff --git a/src/backend/access/spgist/spgscan.c b/src/backend/access/spgist/spgscan.c
index 25893050c58..cc26ea1ab04 100644
--- a/src/backend/access/spgist/spgscan.c
+++ b/src/backend/access/spgist/spgscan.c
@@ -137,7 +137,7 @@ spgAddStartItem(SpGistScanOpaque so, bool isnull)
 				   FirstOffsetNumber);
 	startEntry->isLeaf = false;
 	startEntry->level = 0;
-	startEntry->value = (Datum) 0;
+	startEntry->value = DummyDatum;
 	startEntry->leafTuple = NULL;
 	startEntry->traversalValue = NULL;
 	startEntry->recheck = false;
@@ -477,7 +477,7 @@ spgNewHeapItem(SpGistScanOpaque so, int level, SpGistLeafTuple leafTuple,
 	 */
 	if (so->want_itup)
 	{
-		item->value = isnull ? (Datum) 0 :
+		item->value = isnull ? DummyDatum :
 			datumCopy(leafValue, so->state.attType.attbyval,
 					  so->state.attType.attlen);
 
@@ -495,7 +495,7 @@ spgNewHeapItem(SpGistScanOpaque so, int level, SpGistLeafTuple leafTuple,
 	}
 	else
 	{
-		item->value = (Datum) 0;
+		item->value = DummyDatum;
 		item->leafTuple = NULL;
 	}
 	item->traversalValue = NULL;
@@ -527,7 +527,7 @@ spgLeafTest(SpGistScanOpaque so, SpGistSearchItem *item,
 	{
 		/* Should not have arrived on a nulls page unless nulls are wanted */
 		Assert(so->searchNulls);
-		leafValue = (Datum) 0;
+		leafValue = DummyDatum;
 		distances = NULL;
 		recheck = false;
 		recheckDistances = false;
@@ -552,7 +552,7 @@ spgLeafTest(SpGistScanOpaque so, SpGistSearchItem *item,
 		in.returnData = so->want_itup;
 		in.leafDatum = SGLTDATUM(leafTuple, &so->state);
 
-		out.leafValue = (Datum) 0;
+		out.leafValue = DummyDatum;
 		out.recheck = false;
 		out.distances = NULL;
 		out.recheckDistances = false;
@@ -644,7 +644,7 @@ spgMakeInnerItem(SpGistScanOpaque so,
 		? datumCopy(out->reconstructedValues[i],
 					so->state.attLeafType.attbyval,
 					so->state.attLeafType.attlen)
-		: (Datum) 0;
+		: DummyDatum;
 
 	item->leafTuple = NULL;
 
diff --git a/src/backend/access/spgist/spgutils.c b/src/backend/access/spgist/spgutils.c
index 9b86c016acb..299cf90fdd5 100644
--- a/src/backend/access/spgist/spgutils.c
+++ b/src/backend/access/spgist/spgutils.c
@@ -1132,7 +1132,7 @@ spgDeformLeafTuple(SpGistLeafTuple tup, TupleDesc tupleDescriptor,
 		 */
 		Assert(!hasNullsMask);
 
-		datums[spgKeyColumn] = (Datum) 0;
+		datums[spgKeyColumn] = DummyDatum;
 		isnulls[spgKeyColumn] = true;
 		return;
 	}
diff --git a/src/backend/access/transam/rmgr.c b/src/backend/access/transam/rmgr.c
index 1b7499726eb..1c56dbc8504 100644
--- a/src/backend/access/transam/rmgr.c
+++ b/src/backend/access/transam/rmgr.c
@@ -166,5 +166,5 @@ pg_get_wal_resource_managers(PG_FUNCTION_ARGS)
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
 
-	return (Datum) 0;
+	return DummyDatum;
 }
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 7918176fc58..dcf13acb38a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -379,7 +379,7 @@ MarkAsPreparing(FullTransactionId fxid, const char *gid,
 	/* on first call, register the exit hook */
 	if (!twophaseExitRegistered)
 	{
-		before_shmem_exit(AtProcExit_Twophase, 0);
+		before_shmem_exit(AtProcExit_Twophase, DummyDatum);
 		twophaseExitRegistered = true;
 	}
 
@@ -559,7 +559,7 @@ LockGXact(const char *gid, Oid user)
 	/* on first call, register the exit hook */
 	if (!twophaseExitRegistered)
 	{
-		before_shmem_exit(AtProcExit_Twophase, 0);
+		before_shmem_exit(AtProcExit_Twophase, DummyDatum);
 		twophaseExitRegistered = true;
 	}
 
diff --git a/src/backend/access/transam/xlogprefetcher.c b/src/backend/access/transam/xlogprefetcher.c
index ed3aacabc98..acdcc6b93f0 100644
--- a/src/backend/access/transam/xlogprefetcher.c
+++ b/src/backend/access/transam/xlogprefetcher.c
@@ -845,7 +845,7 @@ pg_stat_get_recovery_prefetch(PG_FUNCTION_ARGS)
 	values[9] = Int32GetDatum(SharedStats->io_depth);
 	tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 
-	return (Datum) 0;
+	return DummyDatum;
 }
 
 /*
diff --git a/src/backend/backup/walsummaryfuncs.c b/src/backend/backup/walsummaryfuncs.c
index d6dd131da14..3ff4961010d 100644
--- a/src/backend/backup/walsummaryfuncs.c
+++ b/src/backend/backup/walsummaryfuncs.c
@@ -58,7 +58,7 @@ pg_available_wal_summaries(PG_FUNCTION_ARGS)
 		tuplestore_puttuple(rsi->setResult, tuple);
 	}
 
-	return (Datum) 0;
+	return DummyDatum;
 }
 
 /*
@@ -167,7 +167,7 @@ pg_wal_summary_contents(PG_FUNCTION_ARGS)
 	DestroyBlockRefTableReader(reader);
 	FileClose(io.file);
 
-	return (Datum) 0;
+	return DummyDatum;
 }
 
 /*
diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y
index 9833f52c1be..6b1b2779f14 100644
--- a/src/backend/bootstrap/bootparse.y
+++ b/src/backend/bootstrap/bootparse.y
@@ -239,7 +239,7 @@ Boot_CreateStmt:
 													  shared_relation,
 													  mapped_relation,
 													  ONCOMMIT_NOOP,
-													  (Datum) 0,
+													  DummyDatum,
 													  false,
 													  true,
 													  false,
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index 9ca8a88dc91..a961b5a0616 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -3101,7 +3101,7 @@ object_aclmask_ext(Oid classid, Oid objectid, Oid roleid,
 	{
 		/* No ACL, so build default ACL */
 		acl = acldefault(get_object_type(classid, objectid), ownerId);
-		aclDatum = (Datum) 0;
+		aclDatum = DummyDatum;
 	}
 	else
 	{
@@ -3338,7 +3338,7 @@ pg_class_aclmask_ext(Oid table_oid, Oid roleid, AclMode mask,
 				acl = acldefault(OBJECT_TABLE, ownerId);
 				break;
 		}
-		aclDatum = (Datum) 0;
+		aclDatum = DummyDatum;
 	}
 	else
 	{
@@ -3430,7 +3430,7 @@ pg_parameter_aclmask(const char *name, Oid roleid, AclMode mask, AclMaskHow how)
 		{
 			/* No ACL, so build default ACL */
 			acl = acldefault(OBJECT_PARAMETER_ACL, BOOTSTRAP_SUPERUSERID);
-			aclDatum = (Datum) 0;
+			aclDatum = DummyDatum;
 		}
 		else
 		{
@@ -3485,7 +3485,7 @@ pg_parameter_acl_aclmask(Oid acl_oid, Oid roleid, AclMode mask, AclMaskHow how)
 	{
 		/* No ACL, so build default ACL */
 		acl = acldefault(OBJECT_PARAMETER_ACL, BOOTSTRAP_SUPERUSERID);
-		aclDatum = (Datum) 0;
+		aclDatum = DummyDatum;
 	}
 	else
 	{
@@ -3565,7 +3565,7 @@ pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid,
 	{
 		/* No ACL, so build default ACL */
 		acl = acldefault(OBJECT_LARGEOBJECT, ownerId);
-		aclDatum = (Datum) 0;
+		aclDatum = DummyDatum;
 	}
 	else
 	{
@@ -3659,7 +3659,7 @@ pg_namespace_aclmask_ext(Oid nsp_oid, Oid roleid,
 	{
 		/* No ACL, so build default ACL */
 		acl = acldefault(OBJECT_SCHEMA, ownerId);
-		aclDatum = (Datum) 0;
+		aclDatum = DummyDatum;
 	}
 	else
 	{
@@ -3795,7 +3795,7 @@ pg_type_aclmask_ext(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how,
 	{
 		/* No ACL, so build default ACL */
 		acl = acldefault(OBJECT_TYPE, ownerId);
-		aclDatum = (Datum) 0;
+		aclDatum = DummyDatum;
 	}
 	else
 	{
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index fd6537567ea..65c1264605d 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -902,7 +902,7 @@ AddNewAttributeTuples(Oid new_rel_oid,
  * Tuple data is taken from new_rel_desc->rd_rel, except for the
  * variable-width fields which are not present in a cached reldesc.
  * relacl and reloptions are passed in Datum form (to avoid having
- * to reference the data types in heap.h).  Pass (Datum) 0 to set them
+ * to reference the data types in heap.h).  Pass DummyDatum to set them
  * to NULL.
  * --------------------------------
  */
@@ -953,11 +953,11 @@ InsertPgClassTuple(Relation pg_class_desc,
 	values[Anum_pg_class_relrewrite - 1] = ObjectIdGetDatum(rd_rel->relrewrite);
 	values[Anum_pg_class_relfrozenxid - 1] = TransactionIdGetDatum(rd_rel->relfrozenxid);
 	values[Anum_pg_class_relminmxid - 1] = MultiXactIdGetDatum(rd_rel->relminmxid);
-	if (relacl != (Datum) 0)
+	if (relacl.value != DummyDatum.value)
 		values[Anum_pg_class_relacl - 1] = relacl;
 	else
 		nulls[Anum_pg_class_relacl - 1] = true;
-	if (reloptions != (Datum) 0)
+	if (reloptions.value != DummyDatum.value)
 		values[Anum_pg_class_reloptions - 1] = reloptions;
 	else
 		nulls[Anum_pg_class_reloptions - 1] = true;
@@ -1104,7 +1104,7 @@ AddNewRelationType(const char *typeName,
  *	shared_relation: true if it's to be a shared relation
  *	mapped_relation: true if the relation will use the relfilenumber map
  *	oncommit: ON COMMIT marking (only relevant if it's a temp table)
- *	reloptions: reloptions in Datum form, or (Datum) 0 if none
+ *	reloptions: reloptions in Datum form, or DummyDatum if none
  *	use_user_acl: true if should look for user-defined default permissions;
  *		if false, relacl is always set NULL
  *	allow_system_table_mods: true to allow creation in system namespaces
@@ -3929,12 +3929,12 @@ StorePartitionKey(Relation rel,
 		pfree(exprString);
 	}
 	else
-		partexprDatum = (Datum) 0;
+		partexprDatum = DummyDatum;
 
 	pg_partitioned_table = table_open(PartitionedRelationId, RowExclusiveLock);
 
 	/* Only this can ever be NULL */
-	if (!partexprDatum)
+	if (!partexprDatum.value)
 		nulls[Anum_pg_partitioned_table_partexprs - 1] = true;
 
 	values[Anum_pg_partitioned_table_partrelid - 1] = ObjectIdGetDatum(RelationGetRelid(rel));
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index c4029a4f3d3..895825c67cf 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -522,7 +522,7 @@ AppendAttributeTuples(Relation indexRelation, const Datum *attopts, const Nullab
 
 		for (int i = 0; i < indexRelation->rd_att->natts; i++)
 		{
-			if (attopts[i])
+			if (attopts[i].value)
 				attrs_extra[i].attoptions.value = attopts[i];
 			else
 				attrs_extra[i].attoptions.isnull = true;
@@ -608,7 +608,7 @@ UpdateIndexRelation(Oid indexoid,
 		pfree(exprsString);
 	}
 	else
-		exprsDatum = (Datum) 0;
+		exprsDatum = DummyDatum;
 
 	/*
 	 * Convert the index predicate (if any) to a text datum.  Note we convert
@@ -623,7 +623,7 @@ UpdateIndexRelation(Oid indexoid,
 		pfree(predString);
 	}
 	else
-		predDatum = (Datum) 0;
+		predDatum = DummyDatum;
 
 
 	/*
@@ -654,10 +654,10 @@ UpdateIndexRelation(Oid indexoid,
 	values[Anum_pg_index_indclass - 1] = PointerGetDatum(indclass);
 	values[Anum_pg_index_indoption - 1] = PointerGetDatum(indoption);
 	values[Anum_pg_index_indexprs - 1] = exprsDatum;
-	if (exprsDatum == (Datum) 0)
+	if (exprsDatum.value == DummyDatum.value)
 		nulls[Anum_pg_index_indexprs - 1] = true;
 	values[Anum_pg_index_indpred - 1] = predDatum;
-	if (predDatum == (Datum) 0)
+	if (predDatum.value == DummyDatum.value)
 		nulls[Anum_pg_index_indpred - 1] = true;
 
 	tuple = heap_form_tuple(RelationGetDescr(pg_index), values, nulls);
@@ -1015,7 +1015,7 @@ index_create(Relation heapRelation,
 	 */
 	InsertPgClassTuple(pg_class, indexRelation,
 					   RelationGetRelid(indexRelation),
-					   (Datum) 0,
+					   DummyDatum,
 					   reloptions);
 
 	/* done with pg_class */
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index d97d632a7ef..9d576cb0b90 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -4522,7 +4522,7 @@ AtEOXact_Namespace(bool isCommit, bool parallel)
 	if (myTempNamespaceSubID != InvalidSubTransactionId && !parallel)
 	{
 		if (isCommit)
-			before_shmem_exit(RemoveTempRelationsCallback, 0);
+			before_shmem_exit(RemoveTempRelationsCallback, DummyDatum);
 		else
 		{
 			myTempNamespace = InvalidOid;
@@ -4765,22 +4765,22 @@ InitializeSearchPath(void)
 		/* namespace name or ACLs may have changed */
 		CacheRegisterSyscacheCallback(NAMESPACEOID,
 									  InvalidationCallback,
-									  (Datum) 0);
+									  DummyDatum);
 
 		/* role name may affect the meaning of "$user" */
 		CacheRegisterSyscacheCallback(AUTHOID,
 									  InvalidationCallback,
-									  (Datum) 0);
+									  DummyDatum);
 
 		/* role membership may affect ACLs */
 		CacheRegisterSyscacheCallback(AUTHMEMROLEMEM,
 									  InvalidationCallback,
-									  (Datum) 0);
+									  DummyDatum);
 
 		/* database owner may affect ACLs */
 		CacheRegisterSyscacheCallback(DATABASEOID,
 									  InvalidationCallback,
-									  (Datum) 0);
+									  DummyDatum);
 
 		/* Force search path to be recomputed on next use */
 		baseSearchPathValid = false;
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index a05f8a87c1f..aee94a9aae3 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -654,7 +654,7 @@ AggregateCreate(const char *aggName,
 	for (i = 0; i < Natts_pg_aggregate; i++)
 	{
 		nulls[i] = false;
-		values[i] = (Datum) NULL;
+		values[i] = DummyDatum;
 		replaces[i] = true;
 	}
 	values[Anum_pg_aggregate_aggfnoid - 1] = ObjectIdGetDatum(procOid);
diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c
index 2d5ac1ea813..fb907fa36f5 100644
--- a/src/backend/catalog/pg_constraint.c
+++ b/src/backend/catalog/pg_constraint.c
@@ -179,7 +179,7 @@ CreateConstraintEntry(const char *constraintName,
 	for (i = 0; i < Natts_pg_constraint; i++)
 	{
 		nulls[i] = false;
-		values[i] = (Datum) NULL;
+		values[i] = DummyDatum;
 	}
 
 	conOid = GetNewOidWithIndex(conDesc, ConstraintOidIndexId,
diff --git a/src/backend/catalog/pg_conversion.c b/src/backend/catalog/pg_conversion.c
index 04cc375caea..67191d24929 100644
--- a/src/backend/catalog/pg_conversion.c
+++ b/src/backend/catalog/pg_conversion.c
@@ -87,7 +87,7 @@ ConversionCreate(const char *conname, Oid connamespace,
 	for (i = 0; i < Natts_pg_conversion; i++)
 	{
 		nulls[i] = false;
-		values[i] = (Datum) NULL;
+		values[i] = DummyDatum;
 	}
 
 	/* form a tuple */
diff --git a/src/backend/catalog/pg_namespace.c b/src/backend/catalog/pg_namespace.c
index 6f5634a4de6..a8bd27ab197 100644
--- a/src/backend/catalog/pg_namespace.c
+++ b/src/backend/catalog/pg_namespace.c
@@ -76,7 +76,7 @@ NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp)
 	for (i = 0; i < Natts_pg_namespace; i++)
 	{
 		nulls[i] = false;
-		values[i] = (Datum) NULL;
+		values[i] = DummyDatum;
 	}
 
 	nspoid = GetNewOidWithIndex(nspdesc, NamespaceOidIndexId,
diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c
index bfcfa643464..bee3e02b155 100644
--- a/src/backend/catalog/pg_operator.c
+++ b/src/backend/catalog/pg_operator.c
@@ -225,7 +225,7 @@ OperatorShellMake(const char *operatorName,
 	for (i = 0; i < Natts_pg_operator; ++i)
 	{
 		nulls[i] = false;
-		values[i] = (Datum) NULL;	/* redundant, but safe */
+		values[i] = DummyDatum;	/* redundant, but safe */
 	}
 
 	/*
@@ -453,7 +453,7 @@ OperatorCreate(const char *operatorName,
 
 	for (i = 0; i < Natts_pg_operator; ++i)
 	{
-		values[i] = (Datum) NULL;
+		values[i] = DummyDatum;
 		replaces[i] = true;
 		nulls[i] = false;
 	}
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 75b17fed15e..d4a130aa704 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -162,7 +162,7 @@ ProcedureCreate(const char *procedureName,
 	/* note: the above is correct, we do NOT count output arguments */
 
 	/* Deconstruct array inputs */
-	if (allParameterTypes != PointerGetDatum(NULL))
+	if (allParameterTypes.value != PointerGetDatum(NULL).value)
 	{
 		/*
 		 * We expect the array to be a 1-D OID array; verify that. We don't
@@ -187,7 +187,7 @@ ProcedureCreate(const char *procedureName,
 		allParams = parameterTypes->values;
 	}
 
-	if (parameterModes != PointerGetDatum(NULL))
+	if (parameterModes.value != PointerGetDatum(NULL).value)
 	{
 		/*
 		 * We expect the array to be a 1-D CHAR array; verify that. We don't
@@ -233,7 +233,7 @@ ProcedureCreate(const char *procedureName,
 	/*
 	 * Apply the same tests to any OUT arguments.
 	 */
-	if (allParameterTypes != PointerGetDatum(NULL))
+	if (allParameterTypes.value != PointerGetDatum(NULL).value)
 	{
 		for (i = 0; i < allParamCount; i++)
 		{
@@ -320,7 +320,7 @@ ProcedureCreate(const char *procedureName,
 	for (i = 0; i < Natts_pg_proc; ++i)
 	{
 		nulls[i] = false;
-		values[i] = (Datum) 0;
+		values[i] = DummyDatum;
 		replaces[i] = true;
 	}
 
@@ -344,15 +344,15 @@ ProcedureCreate(const char *procedureName,
 	values[Anum_pg_proc_pronargdefaults - 1] = UInt16GetDatum(list_length(parameterDefaults));
 	values[Anum_pg_proc_prorettype - 1] = ObjectIdGetDatum(returnType);
 	values[Anum_pg_proc_proargtypes - 1] = PointerGetDatum(parameterTypes);
-	if (allParameterTypes != PointerGetDatum(NULL))
+	if (allParameterTypes.value != PointerGetDatum(NULL).value)
 		values[Anum_pg_proc_proallargtypes - 1] = allParameterTypes;
 	else
 		nulls[Anum_pg_proc_proallargtypes - 1] = true;
-	if (parameterModes != PointerGetDatum(NULL))
+	if (parameterModes.value != PointerGetDatum(NULL).value)
 		values[Anum_pg_proc_proargmodes - 1] = parameterModes;
 	else
 		nulls[Anum_pg_proc_proargmodes - 1] = true;
-	if (parameterNames != PointerGetDatum(NULL))
+	if (parameterNames.value != PointerGetDatum(NULL).value)
 		values[Anum_pg_proc_proargnames - 1] = parameterNames;
 	else
 		nulls[Anum_pg_proc_proargnames - 1] = true;
@@ -360,7 +360,7 @@ ProcedureCreate(const char *procedureName,
 		values[Anum_pg_proc_proargdefaults - 1] = CStringGetTextDatum(nodeToString(parameterDefaults));
 	else
 		nulls[Anum_pg_proc_proargdefaults - 1] = true;
-	if (trftypes != PointerGetDatum(NULL))
+	if (trftypes.value != PointerGetDatum(NULL).value)
 		values[Anum_pg_proc_protrftypes - 1] = trftypes;
 	else
 		nulls[Anum_pg_proc_protrftypes - 1] = true;
@@ -373,7 +373,7 @@ ProcedureCreate(const char *procedureName,
 		values[Anum_pg_proc_prosqlbody - 1] = CStringGetTextDatum(nodeToString(prosqlbody));
 	else
 		nulls[Anum_pg_proc_prosqlbody - 1] = true;
-	if (proconfig != PointerGetDatum(NULL))
+	if (proconfig.value != PointerGetDatum(NULL).value)
 		values[Anum_pg_proc_proconfig - 1] = proconfig;
 	else
 		nulls[Anum_pg_proc_proconfig - 1] = true;
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index b36f81afb9d..384d26ead2a 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -80,7 +80,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
 	for (i = 0; i < Natts_pg_type; ++i)
 	{
 		nulls[i] = false;
-		values[i] = (Datum) NULL;	/* redundant, but safe */
+		values[i] = DummyDatum;	/* redundant, but safe */
 	}
 
 	/*
@@ -343,7 +343,7 @@ TypeCreate(Oid newTypeOid,
 	{
 		nulls[i] = false;
 		replaces[i] = true;
-		values[i] = (Datum) 0;
+		values[i] = DummyDatum;
 	}
 
 	/*
diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c
index 874a8fc89ad..145cff6e3fe 100644
--- a/src/backend/catalog/toasting.c
+++ b/src/backend/catalog/toasting.c
@@ -47,7 +47,7 @@ static bool needs_toast_table(Relation rel);
  *		If the table needs a toast table, and doesn't already have one,
  *		then create a toast table for it.
  *
- * reloptions for the toast table can be passed, too.  Pass (Datum) 0
+ * reloptions for the toast table can be passed, too.  Pass DummyDatum
  * for default reloptions.
  *
  * We expect the caller to have verified that the relation is a table and have
@@ -107,7 +107,7 @@ BootstrapToastTable(char *relName, Oid toastOid, Oid toastIndexOid)
 			 relName);
 
 	/* create_toast_table does all the work */
-	if (!create_toast_table(rel, toastOid, toastIndexOid, (Datum) 0,
+	if (!create_toast_table(rel, toastOid, toastIndexOid, DummyDatum,
 							AccessExclusiveLock, false, InvalidOid))
 		elog(ERROR, "\"%s\" does not require a toast table",
 			 relName);
@@ -324,7 +324,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
 				 list_make2("chunk_id", "chunk_seq"),
 				 BTREE_AM_OID,
 				 rel->rd_rel->reltablespace,
-				 collationIds, opclassIds, NULL, coloptions, NULL, (Datum) 0,
+				 collationIds, opclassIds, NULL, coloptions, NULL, DummyDatum,
 				 INDEX_CREATE_IS_PRIMARY, 0, true, true, NULL);
 
 	table_close(toast_rel, NoLock);
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index 7111d5d5334..8ad892afba1 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -967,7 +967,7 @@ compute_index_stats(Relation onerel, double totalrows,
 
 					if (isnull[attnum - 1])
 					{
-						exprvals[tcnt] = (Datum) 0;
+						exprvals[tcnt] = DummyDatum;
 						exprnulls[tcnt] = true;
 					}
 					else
@@ -1727,7 +1727,7 @@ update_attstats(Oid relid, bool inh, int natts, VacAttrStats **vacattrstats)
 			else
 			{
 				nulls[i] = true;
-				values[i++] = (Datum) 0;
+				values[i++] = DummyDatum;
 			}
 		}
 		i = Anum_pg_statistic_stavalues1 - 1;
@@ -1748,7 +1748,7 @@ update_attstats(Oid relid, bool inh, int natts, VacAttrStats **vacattrstats)
 			else
 			{
 				nulls[i] = true;
-				values[i++] = (Datum) 0;
+				values[i++] = DummyDatum;
 			}
 		}
 
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 4bd37d5beb5..84351c92ffc 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -1060,7 +1060,7 @@ Exec_ListenPreCommit(void)
 	 */
 	if (!unlistenExitRegistered)
 	{
-		before_shmem_exit(Async_UnlistenOnExit, 0);
+		before_shmem_exit(Async_UnlistenOnExit, DummyDatum);
 		unlistenExitRegistered = true;
 	}
 
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index b55221d44cd..b46b523dfe5 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -734,7 +734,7 @@ make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, Oid NewAccessMethod,
 	reloptions = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions,
 								 &isNull);
 	if (isNull)
-		reloptions = (Datum) 0;
+		reloptions = DummyDatum;
 
 	if (relpersistence == RELPERSISTENCE_TEMP)
 		namespaceid = LookupCreationNamespace("pg_temp");
@@ -807,7 +807,7 @@ make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, Oid NewAccessMethod,
 		reloptions = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions,
 									 &isNull);
 		if (isNull)
-			reloptions = (Datum) 0;
+			reloptions = DummyDatum;
 
 		NewHeapCreateToastTable(OIDNewHeap, reloptions, lockmode, toastid);
 
diff --git a/src/backend/commands/createas.c b/src/backend/commands/createas.c
index dfd2ab8e862..7f82c46a780 100644
--- a/src/backend/commands/createas.c
+++ b/src/backend/commands/createas.c
@@ -121,7 +121,7 @@ create_ctas_internal(List *attrList, IntoClause *into)
 	CommandCounterIncrement();
 
 	/* parse and validate reloptions for the toast table */
-	toast_options = transformRelOptions((Datum) 0,
+	toast_options = transformRelOptions(DummyDatum,
 										create->options,
 										"toast",
 										validnsps,
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index 631fb0525f1..4cbadf1678d 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -1475,7 +1475,7 @@ pg_event_trigger_dropped_objects(PG_FUNCTION_ARGS)
 							 values, nulls);
 	}
 
-	return (Datum) 0;
+	return DummyDatum;
 }
 
 /*
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index e6f9ab6dfd6..1fefa5c4ad0 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -1257,7 +1257,7 @@ execute_extension_script(Oid extensionOid, ExtensionControlFile *control,
 											t_sql,
 											CStringGetTextDatum("@extschema@"),
 											CStringGetTextDatum(qSchemaName));
-			if (t_sql != old && strpbrk(schemaName, quoting_relevant_chars))
+			if (t_sql.value != old.value && strpbrk(schemaName, quoting_relevant_chars))
 				ereport(ERROR,
 						(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 						 errmsg("invalid character in extension \"%s\" schema: must not contain any of \"%s\"",
@@ -1284,7 +1284,7 @@ execute_extension_script(Oid extensionOid, ExtensionControlFile *control,
 											t_sql,
 											CStringGetTextDatum(repltoken),
 											CStringGetTextDatum(qSchemaName));
-			if (t_sql != old && strpbrk(schemaName, quoting_relevant_chars))
+			if (t_sql.value != old.value && strpbrk(schemaName, quoting_relevant_chars))
 				ereport(ERROR,
 						(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 						 errmsg("invalid character in extension \"%s\" schema: must not contain any of \"%s\"",
@@ -2093,12 +2093,12 @@ InsertExtensionTuple(const char *extName, Oid extOwner,
 	values[Anum_pg_extension_extrelocatable - 1] = BoolGetDatum(relocatable);
 	values[Anum_pg_extension_extversion - 1] = CStringGetTextDatum(extVersion);
 
-	if (extConfig == PointerGetDatum(NULL))
+	if (extConfig.value == PointerGetDatum(NULL).value)
 		nulls[Anum_pg_extension_extconfig - 1] = true;
 	else
 		values[Anum_pg_extension_extconfig - 1] = extConfig;
 
-	if (extCondition == PointerGetDatum(NULL))
+	if (extCondition.value == PointerGetDatum(NULL).value)
 		nulls[Anum_pg_extension_extcondition - 1] = true;
 	else
 		values[Anum_pg_extension_extcondition - 1] = extCondition;
@@ -2275,7 +2275,7 @@ pg_available_extensions(PG_FUNCTION_ARGS)
 		}
 	}
 
-	return (Datum) 0;
+	return DummyDatum;
 }
 
 /*
@@ -2344,7 +2344,7 @@ pg_available_extension_versions(PG_FUNCTION_ARGS)
 		}
 	}
 
-	return (Datum) 0;
+	return DummyDatum;
 }
 
 /*
@@ -2625,7 +2625,7 @@ pg_extension_update_paths(PG_FUNCTION_ARGS)
 		}
 	}
 
-	return (Datum) 0;
+	return DummyDatum;
 }
 
 /*
@@ -2861,7 +2861,7 @@ pg_get_loaded_modules(PG_FUNCTION_ARGS)
 							 values, nulls);
 	}
 
-	return (Datum) 0;
+	return DummyDatum;
 }
 
 /*
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 0335e982b31..d2e0c0545e9 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -493,7 +493,7 @@ interpret_function_parameter_list(ParseState *pstate,
 	{
 		for (i = 0; i < parameterCount; i++)
 		{
-			if (paramNames[i] == PointerGetDatum(NULL))
+			if (paramNames[i].value == PointerGetDatum(NULL).value)
 				paramNames[i] = CStringGetTextDatum("");
 		}
 		*parameterNames = construct_array_builtin(paramNames, parameterCount, TEXTOID);
@@ -1506,7 +1506,7 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt)
 
 		if (a == NULL)
 		{
-			repl_val[Anum_pg_proc_proconfig - 1] = (Datum) 0;
+			repl_val[Anum_pg_proc_proconfig - 1] = DummyDatum;
 			repl_null[Anum_pg_proc_proconfig - 1] = true;
 		}
 		else
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 6f753ab6d7a..9fc69e13944 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -370,17 +370,17 @@ CompareOpclassOptions(const Datum *opts1, const Datum *opts2, int natts)
 	fmgr_info(F_ARRAY_EQ, &fm);
 	for (i = 0; i < natts; i++)
 	{
-		Datum		opt1 = opts1 ? opts1[i] : (Datum) 0;
-		Datum		opt2 = opts2 ? opts2[i] : (Datum) 0;
+		Datum		opt1 = opts1 ? opts1[i] : DummyDatum;
+		Datum		opt2 = opts2 ? opts2[i] : DummyDatum;
 
-		if (opt1 == (Datum) 0)
+		if (opt1.value == DummyDatum.value)
 		{
-			if (opt2 == (Datum) 0)
+			if (opt2.value == DummyDatum.value)
 				continue;
 			else
 				return false;
 		}
-		else if (opt2 == (Datum) 0)
+		else if (opt2.value == DummyDatum.value)
 			return false;
 
 		/*
@@ -908,7 +908,7 @@ DefineIndex(Oid tableId,
 	/*
 	 * Parse AM-specific options, convert to text array form, validate.
 	 */
-	reloptions = transformRelOptions((Datum) 0, stmt->options,
+	reloptions = transformRelOptions(DummyDatum, stmt->options,
 									 NULL, NULL, false, false);
 
 	(void) index_reloptions(amoptions, reloptions, true);
@@ -2046,7 +2046,7 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
 						 errmsg("including column does not support NULLS FIRST/LAST options")));
 
 			opclassOids[attn] = InvalidOid;
-			opclassOptions[attn] = (Datum) 0;
+			opclassOptions[attn] = DummyDatum;
 			colOptions[attn] = 0;
 			collationOids[attn] = InvalidOid;
 			attn++;
@@ -2240,11 +2240,11 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
 			Assert(attn < nkeycols);
 
 			opclassOptions[attn] =
-				transformRelOptions((Datum) 0, attribute->opclassopts,
+				transformRelOptions(DummyDatum, attribute->opclassopts,
 									NULL, NULL, false, false);
 		}
 		else
-			opclassOptions[attn] = (Datum) 0;
+			opclassOptions[attn] = DummyDatum;
 
 		attn++;
 	}
diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c
index 673648f1fc6..c2b9de95c1c 100644
--- a/src/backend/commands/operatorcmds.c
+++ b/src/backend/commands/operatorcmds.c
@@ -648,7 +648,7 @@ AlterOperator(AlterOperatorStmt *stmt)
 	/* Update the tuple */
 	for (i = 0; i < Natts_pg_operator; ++i)
 	{
-		values[i] = (Datum) 0;
+		values[i] = DummyDatum;
 		replaces[i] = false;
 		nulls[i] = false;
 	}
diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c
index 34b6410d6a2..c87cac06a7b 100644
--- a/src/backend/commands/prepare.c
+++ b/src/backend/commands/prepare.c
@@ -735,7 +735,7 @@ pg_prepared_statement(PG_FUNCTION_ARGS)
 		}
 	}
 
-	return (Datum) 0;
+	return DummyDatum;
 }
 
 /*
diff --git a/src/backend/commands/statscmds.c b/src/backend/commands/statscmds.c
index e24d540cd45..f8a836e5e20 100644
--- a/src/backend/commands/statscmds.c
+++ b/src/backend/commands/statscmds.c
@@ -497,7 +497,7 @@ CreateStatistics(CreateStatsStmt *stmt)
 		pfree(exprsString);
 	}
 	else
-		exprsDatum = (Datum) 0;
+		exprsDatum = DummyDatum;
 
 	statrel = table_open(StatisticExtRelationId, RowExclusiveLock);
 
@@ -519,7 +519,7 @@ CreateStatistics(CreateStatsStmt *stmt)
 	values[Anum_pg_statistic_ext_stxkind - 1] = PointerGetDatum(stxkind);
 
 	values[Anum_pg_statistic_ext_stxexprs - 1] = exprsDatum;
-	if (exprsDatum == (Datum) 0)
+	if (exprsDatum.value == DummyDatum.value)
 		nulls[Anum_pg_statistic_ext_stxexprs - 1] = true;
 
 	/* insert it into pg_statistic_ext */
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index c6dd2e020da..da17d4c793c 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -929,7 +929,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
 	/*
 	 * Parse and validate reloptions, if any.
 	 */
-	reloptions = transformRelOptions((Datum) 0, stmt->options, NULL, validnsps,
+	reloptions = transformRelOptions(DummyDatum, stmt->options, NULL, validnsps,
 									 true, false);
 
 	switch (relkind)
@@ -5354,7 +5354,7 @@ ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode,
 			  tab->relkind == RELKIND_PARTITIONED_TABLE) &&
 			 tab->partition_constraint == NULL) ||
 			tab->relkind == RELKIND_MATVIEW)
-			AlterTableCreateToastTable(tab->relid, (Datum) 0, lockmode);
+			AlterTableCreateToastTable(tab->relid, DummyDatum, lockmode);
 	}
 }
 
@@ -9049,7 +9049,7 @@ ATExecSetOptions(Relation rel, const char *colName, Node *options,
 	/* Generate new proposed attoptions (text array) */
 	datum = SysCacheGetAttr(ATTNAME, tuple, Anum_pg_attribute_attoptions,
 							&isnull);
-	newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
+	newOptions = transformRelOptions(isnull ? DummyDatum : datum,
 									 castNode(List, options), NULL, NULL,
 									 false, isReset);
 	/* Validate new options */
@@ -9058,7 +9058,7 @@ ATExecSetOptions(Relation rel, const char *colName, Node *options,
 	/* Build new tuple. */
 	memset(repl_null, false, sizeof(repl_null));
 	memset(repl_repl, false, sizeof(repl_repl));
-	if (newOptions != (Datum) 0)
+	if (newOptions.value != DummyDatum.value)
 		repl_val[Anum_pg_attribute_attoptions - 1] = newOptions;
 	else
 		repl_null[Anum_pg_attribute_attoptions - 1] = true;
@@ -16637,7 +16637,7 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
 		 * If we're supposed to replace the reloptions list, we just pretend
 		 * there were none before.
 		 */
-		datum = (Datum) 0;
+		datum = DummyDatum;
 	}
 	else
 	{
@@ -16647,7 +16647,7 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
 		datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions,
 								&isnull);
 		if (isnull)
-			datum = (Datum) 0;
+			datum = DummyDatum;
 	}
 
 	/* Generate new proposed reloptions (text array) */
@@ -16723,7 +16723,7 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
 	memset(repl_null, false, sizeof(repl_null));
 	memset(repl_repl, false, sizeof(repl_repl));
 
-	if (newOptions != (Datum) 0)
+	if (newOptions.value != DummyDatum.value)
 		repl_val[Anum_pg_class_reloptions - 1] = newOptions;
 	else
 		repl_null[Anum_pg_class_reloptions - 1] = true;
@@ -16761,7 +16761,7 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
 			 * If we're supposed to replace the reloptions list, we just
 			 * pretend there were none before.
 			 */
-			datum = (Datum) 0;
+			datum = DummyDatum;
 		}
 		else
 		{
@@ -16771,7 +16771,7 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
 			datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions,
 									&isnull);
 			if (isnull)
-				datum = (Datum) 0;
+				datum = DummyDatum;
 		}
 
 		newOptions = transformRelOptions(datum, defList, "toast", validnsps,
@@ -16783,7 +16783,7 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
 		memset(repl_null, false, sizeof(repl_null));
 		memset(repl_repl, false, sizeof(repl_repl));
 
-		if (newOptions != (Datum) 0)
+		if (newOptions.value != DummyDatum.value)
 			repl_val[Anum_pg_class_reloptions - 1] = newOptions;
 		else
 			repl_null[Anum_pg_class_reloptions - 1] = true;
@@ -21300,7 +21300,7 @@ DetachPartitionFinalize(Relation rel, Relation partRel, bool concurrent,
 	memset(new_val, 0, sizeof(new_val));
 	memset(new_null, false, sizeof(new_null));
 	memset(new_repl, false, sizeof(new_repl));
-	new_val[Anum_pg_class_relpartbound - 1] = (Datum) 0;
+	new_val[Anum_pg_class_relpartbound - 1] = DummyDatum;
 	new_null[Anum_pg_class_relpartbound - 1] = true;
 	new_repl[Anum_pg_class_relpartbound - 1] = true;
 	newtuple = heap_modify_tuple(tuple, RelationGetDescr(classRel),
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index df31eace47a..f6bce7d34ce 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -333,11 +333,11 @@ CreateTableSpace(CreateTableSpaceStmt *stmt)
 	nulls[Anum_pg_tablespace_spcacl - 1] = true;
 
 	/* Generate new proposed spcoptions (text array) */
-	newOptions = transformRelOptions((Datum) 0,
+	newOptions = transformRelOptions(DummyDatum,
 									 stmt->options,
 									 NULL, NULL, false, false);
 	(void) tablespace_reloptions(newOptions, true);
-	if (newOptions != (Datum) 0)
+	if (newOptions.value != DummyDatum.value)
 		values[Anum_pg_tablespace_spcoptions - 1] = newOptions;
 	else
 		nulls[Anum_pg_tablespace_spcoptions - 1] = true;
@@ -1052,7 +1052,7 @@ AlterTableSpaceOptions(AlterTableSpaceOptionsStmt *stmt)
 	/* Generate new proposed spcoptions (text array) */
 	datum = heap_getattr(tup, Anum_pg_tablespace_spcoptions,
 						 RelationGetDescr(rel), &isnull);
-	newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
+	newOptions = transformRelOptions(isnull ? DummyDatum : datum,
 									 stmt->options, NULL, NULL, false,
 									 stmt->isReset);
 	(void) tablespace_reloptions(newOptions, true);
@@ -1060,7 +1060,7 @@ AlterTableSpaceOptions(AlterTableSpaceOptionsStmt *stmt)
 	/* Build new tuple. */
 	memset(repl_null, false, sizeof(repl_null));
 	memset(repl_repl, false, sizeof(repl_repl));
-	if (newOptions != (Datum) 0)
+	if (newOptions.value != DummyDatum.value)
 		repl_val[Anum_pg_tablespace_spcoptions - 1] = newOptions;
 	else
 		repl_null[Anum_pg_tablespace_spcoptions - 1] = true;
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index c909d1b8bd8..ada433ab7ba 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -6676,7 +6676,7 @@ check_modified_virtual_generated(TupleDesc tupdesc, HeapTuple tuple)
 			if (!heap_attisnull(tuple, i + 1, tupdesc))
 			{
 				int			replCol = i + 1;
-				Datum		replValue = 0;
+				Datum		replValue = DummyDatum;
 				bool		replIsnull = true;
 
 				tuple = heap_modify_tuple_by_cols(tuple, tupdesc, 1, &replCol, &replValue, &replIsnull);
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index dc7df736fb8..eb979210d0c 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -1244,7 +1244,7 @@ getTokenTypes(Oid prsId, List *tokennames)
 
 	/* lextype takes one dummy argument */
 	list = (LexDescr *) DatumGetPointer(OidFunctionCall1(prs->lextypeOid,
-														 (Datum) 0));
+														 DummyDatum));
 
 	foreach(tn, tokennames)
 	{
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index 1e3d4ab0e20..fe90d24a857 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -389,7 +389,7 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
 	}
 	else
 	{
-		validUntil_datum = (Datum) 0;
+		validUntil_datum = DummyDatum;
 		validUntil_null = true;
 	}
 
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index f1569879b52..74ae427461d 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -724,7 +724,7 @@ ExecBuildUpdateProjection(List *targetList,
 			scratch.opcode = EEOP_CONST;
 			scratch.resvalue = &state->resvalue;
 			scratch.resnull = &state->resnull;
-			scratch.d.constval.value = (Datum) 0;
+			scratch.d.constval.value = DummyDatum;
 			scratch.d.constval.isnull = true;
 			ExprEvalPushStep(state, &scratch);
 			/* ... then assign it to the result slot */
@@ -1477,7 +1477,7 @@ ExecInitExprRec(Expr *node, ExprState *state,
 				if (subplan->subLinkType == MULTIEXPR_SUBLINK)
 				{
 					scratch.opcode = EEOP_CONST;
-					scratch.d.constval.value = (Datum) 0;
+					scratch.d.constval.value = DummyDatum;
 					scratch.d.constval.isnull = true;
 					ExprEvalPushStep(state, &scratch);
 					break;
@@ -4833,7 +4833,7 @@ ExecInitJsonExpr(JsonExpr *jsexpr, ExprState *state,
 	scratch->opcode = EEOP_CONST;
 	scratch->resvalue = resv;
 	scratch->resnull = resnull;
-	scratch->d.constval.value = (Datum) 0;
+	scratch->d.constval.value = DummyDatum;
 	scratch->d.constval.isnull = true;
 	ExprEvalPushStep(state, scratch);
 
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 0e1a74976f7..193b262110c 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -628,7 +628,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
 		EEO_CASE(EEOP_DONE_NO_RETURN)
 		{
 			Assert(isnull == NULL);
-			return (Datum) 0;
+			return DummyDatum;
 		}
 
 		EEO_CASE(EEOP_INNER_FETCHSOME)
@@ -1078,7 +1078,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
 			}
 			else if (*op->d.boolexpr.anynull)
 			{
-				*op->resvalue = (Datum) 0;
+				*op->resvalue = DummyDatum;
 				*op->resnull = true;
 			}
 			else
@@ -1145,7 +1145,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
 			}
 			else if (*op->d.boolexpr.anynull)
 			{
-				*op->resvalue = (Datum) 0;
+				*op->resvalue = DummyDatum;
 				*op->resnull = true;
 			}
 			else
@@ -1535,7 +1535,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
 				/* if the arguments are equal return null */
 				if (!fcinfo->isnull && DatumGetBool(result))
 				{
-					*op->resvalue = (Datum) 0;
+					*op->resvalue = DummyDatum;
 					*op->resnull = true;
 
 					EEO_NEXT();
@@ -1587,7 +1587,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
 			 */
 			if (state->flags & op->d.returningexpr.nullflag)
 			{
-				*op->resvalue = (Datum) 0;
+				*op->resvalue = DummyDatum;
 				*op->resnull = true;
 
 				EEO_JUMP(op->d.returningexpr.jumpdone);
@@ -1815,7 +1815,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
 			if (!fcinfo->args[0].isnull)
 				*op->resvalue = op->d.hashdatum.fn_addr(fcinfo);
 			else
-				*op->resvalue = (Datum) 0;
+				*op->resvalue = DummyDatum;
 
 			*op->resnull = false;
 
@@ -1834,7 +1834,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
 				 * finding a NULL.
 				 */
 				*op->resnull = true;
-				*op->resvalue = (Datum) 0;
+				*op->resvalue = DummyDatum;
 				EEO_JUMP(op->d.hashdatum.jumpdone);
 			}
 
@@ -1882,7 +1882,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
 				 * finding a NULL.
 				 */
 				*op->resnull = true;
-				*op->resvalue = (Datum) 0;
+				*op->resvalue = DummyDatum;
 				EEO_JUMP(op->d.hashdatum.jumpdone);
 			}
 			else
@@ -2275,7 +2275,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
 
 out_error:
 	pg_unreachable();
-	return (Datum) 0;
+	return DummyDatum;
 }
 
 /*
@@ -2602,7 +2602,7 @@ ExecJustAssignVarImpl(ExprState *state, TupleTableSlot *inslot, bool *isnull)
 	Assert(resultnum >= 0 && resultnum < outslot->tts_tupleDescriptor->natts);
 	outslot->tts_values[resultnum] =
 		slot_getattr(inslot, attnum, &outslot->tts_isnull[resultnum]);
-	return 0;
+	return DummyDatum;
 }
 
 /* Evaluate inner Var and assign to appropriate column of result tuple */
@@ -2655,7 +2655,7 @@ ExecJustApplyFuncToCase(ExprState *state, ExprContext *econtext, bool *isnull)
 		if (args[argno].isnull)
 		{
 			*isnull = true;
-			return (Datum) 0;
+			return DummyDatum;
 		}
 	}
 	fcinfo->isnull = false;
@@ -2736,7 +2736,7 @@ ExecJustAssignVarVirtImpl(ExprState *state, TupleTableSlot *inslot, bool *isnull
 	outslot->tts_values[resultnum] = inslot->tts_values[attnum];
 	outslot->tts_isnull[resultnum] = inslot->tts_isnull[attnum];
 
-	return 0;
+	return DummyDatum;
 }
 
 /* Like ExecJustAssignInnerVar, optimized for virtual slots */
@@ -2817,7 +2817,7 @@ ExecJustHashVarImpl(ExprState *state, TupleTableSlot *slot, bool *isnull)
 	if (!fcinfo->args[0].isnull)
 		return hashop->d.hashdatum.fn_addr(fcinfo);
 	else
-		return (Datum) 0;
+		return DummyDatum;
 }
 
 /* implementation for hashing an outer Var */
@@ -2851,7 +2851,7 @@ ExecJustHashVarVirtImpl(ExprState *state, TupleTableSlot *slot, bool *isnull)
 	if (!fcinfo->args[0].isnull)
 		return hashop->d.hashdatum.fn_addr(fcinfo);
 	else
-		return (Datum) 0;
+		return DummyDatum;
 }
 
 /* Like ExecJustHashInnerVar, optimized for virtual slots */
@@ -2898,7 +2898,7 @@ ExecJustHashOuterVarStrict(ExprState *state, ExprContext *econtext,
 	{
 		/* return NULL on NULL input */
 		*isnull = true;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 }
 
@@ -3176,7 +3176,7 @@ ExecEvalCoerceViaIOSafe(ExprState *state, ExprEvalStep *op)
 		if (SOFT_ERROR_OCCURRED(fcinfo_in->context))
 		{
 			*op->resnull = true;
-			*op->resvalue = (Datum) 0;
+			*op->resvalue = DummyDatum;
 			return;
 		}
 
@@ -4104,7 +4104,7 @@ ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op)
 		/* Get array element, checking for NULL */
 		if (bitmap && (*bitmap & bitmask) == 0)
 		{
-			fcinfo->args[1].value = (Datum) 0;
+			fcinfo->args[1].value = DummyDatum;
 			fcinfo->args[1].isnull = true;
 		}
 		else
@@ -4120,7 +4120,7 @@ ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op)
 		if (fcinfo->args[1].isnull && strictfunc)
 		{
 			fcinfo->isnull = true;
-			thisresult = (Datum) 0;
+			thisresult = DummyDatum;
 		}
 		else
 		{
@@ -4368,7 +4368,7 @@ ExecEvalHashedScalarArrayOp(ExprState *state, ExprEvalStep *op, ExprContext *eco
 			 * We have nulls in the array so a non-null lhs and no match must
 			 * yield NULL.
 			 */
-			result = (Datum) 0;
+			result = DummyDatum;
 			resultnull = true;
 		}
 		else
@@ -4382,7 +4382,7 @@ ExecEvalHashedScalarArrayOp(ExprState *state, ExprEvalStep *op, ExprContext *eco
 			 */
 			fcinfo->args[0].value = scalar;
 			fcinfo->args[0].isnull = scalar_isnull;
-			fcinfo->args[1].value = (Datum) 0;
+			fcinfo->args[1].value = DummyDatum;
 			fcinfo->args[1].isnull = true;
 
 			result = op->d.hashedscalararrayop.finfo->fn_addr(fcinfo);
@@ -4445,7 +4445,7 @@ ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op)
 	Datum		value;
 
 	*op->resnull = true;		/* until we get a result */
-	*op->resvalue = (Datum) 0;
+	*op->resvalue = DummyDatum;
 
 	switch (xexpr->op)
 	{
@@ -4684,7 +4684,7 @@ ExecEvalJsonConstructor(ExprState *state, ExprEvalStep *op,
 	{
 		if (jcstate->arg_nulls[0])
 		{
-			res = (Datum) 0;
+			res = DummyDatum;
 			isnull = true;
 		}
 		else
@@ -4704,7 +4704,7 @@ ExecEvalJsonConstructor(ExprState *state, ExprEvalStep *op,
 	{
 		if (jcstate->arg_nulls[0])
 		{
-			res = (Datum) 0;
+			res = DummyDatum;
 			isnull = true;
 		}
 		else
@@ -4895,7 +4895,7 @@ ExecEvalJsonExprPath(ExprState *state, ExprEvalStep *op,
 				if (jbv == NULL)
 				{
 					/* Will be coerced with json_populate_type(), if needed. */
-					*op->resvalue = (Datum) 0;
+					*op->resvalue = DummyDatum;
 					*op->resnull = true;
 				}
 				else if (!error && !empty)
@@ -4972,7 +4972,7 @@ ExecEvalJsonExprPath(ExprState *state, ExprEvalStep *op,
 	/* Handle ON EMPTY. */
 	if (empty)
 	{
-		*op->resvalue = (Datum) 0;
+		*op->resvalue = DummyDatum;
 		*op->resnull = true;
 		if (jsexpr->on_empty)
 		{
@@ -5015,7 +5015,7 @@ ExecEvalJsonExprPath(ExprState *state, ExprEvalStep *op,
 	if (error)
 	{
 		Assert(!throw_error);
-		*op->resvalue = (Datum) 0;
+		*op->resvalue = DummyDatum;
 		*op->resnull = true;
 		jsestate->error.value = BoolGetDatum(true);
 		/* Set up to catch coercion errors of the ON ERROR value. */
@@ -5137,7 +5137,7 @@ ExecEvalJsonCoercion(ExprState *state, ExprEvalStep *op,
 								   (Node *) escontext))
 			{
 				*op->resnull = true;
-				*op->resvalue = (Datum) 0;
+				*op->resvalue = DummyDatum;
 			}
 			else
 				*op->resvalue = DirectFunctionCall1(bool_int4, *op->resvalue);
@@ -5218,7 +5218,7 @@ ExecEvalJsonCoercionFinish(ExprState *state, ExprEvalStep *op)
 							GetJsonBehaviorValueString(jsestate->jsexpr->on_empty)),
 					 errdetail("%s", jsestate->escontext.error_data->message)));
 
-		*op->resvalue = (Datum) 0;
+		*op->resvalue = DummyDatum;
 		*op->resnull = true;
 
 		jsestate->error.value = BoolGetDatum(true);
@@ -5368,7 +5368,7 @@ ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 				case VAR_RETURNING_OLD:
 					if (state->flags & EEO_FLAG_OLD_IS_NULL)
 					{
-						*op->resvalue = (Datum) 0;
+						*op->resvalue = DummyDatum;
 						*op->resnull = true;
 						return;
 					}
@@ -5378,7 +5378,7 @@ ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 				case VAR_RETURNING_NEW:
 					if (state->flags & EEO_FLAG_NEW_IS_NULL)
 					{
-						*op->resvalue = (Datum) 0;
+						*op->resvalue = DummyDatum;
 						*op->resnull = true;
 						return;
 					}
@@ -5593,7 +5593,7 @@ ExecEvalSysVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
 		(op->d.var.varreturningtype == VAR_RETURNING_NEW &&
 		 state->flags & EEO_FLAG_NEW_IS_NULL))
 	{
-		*op->resvalue = (Datum) 0;
+		*op->resvalue = DummyDatum;
 		*op->resnull = true;
 		return;
 	}
@@ -5670,7 +5670,7 @@ ExecAggCopyTransValue(AggState *aggstate, AggStatePerTrans pertrans,
 					  Datum newValue, bool newValueIsNull,
 					  Datum oldValue, bool oldValueIsNull)
 {
-	Assert(newValue != oldValue);
+	Assert(newValue.value != oldValue.value);
 
 	if (!newValueIsNull)
 	{
@@ -5692,7 +5692,7 @@ ExecAggCopyTransValue(AggState *aggstate, AggStatePerTrans pertrans,
 		 * callers can safely compare newValue/oldValue without having to
 		 * check their respective nullness.
 		 */
-		newValue = (Datum) 0;
+		newValue = DummyDatum;
 	}
 
 	if (!oldValueIsNull)
@@ -5743,7 +5743,7 @@ ExecEvalPreOrderedDistinctSingle(AggState *aggstate, AggStatePerTrans pertrans)
 			MemoryContextSwitchTo(oldContext);
 		}
 		else
-			pertrans->lastdatum = (Datum) 0;
+			pertrans->lastdatum = DummyDatum;
 		pertrans->lastisnull = isnull;
 		return true;
 	}
diff --git a/src/backend/executor/execJunk.c b/src/backend/executor/execJunk.c
index 3f196de1ad2..00865616f19 100644
--- a/src/backend/executor/execJunk.c
+++ b/src/backend/executor/execJunk.c
@@ -287,7 +287,7 @@ ExecFilterJunk(JunkFilter *junkfilter, TupleTableSlot *slot)
 
 		if (j == 0)
 		{
-			values[i] = (Datum) 0;
+			values[i] = DummyDatum;
 			isnull[i] = true;
 		}
 		else
diff --git a/src/backend/executor/execSRF.c b/src/backend/executor/execSRF.c
index a03fe780a02..4ac4f9035c5 100644
--- a/src/backend/executor/execSRF.c
+++ b/src/backend/executor/execSRF.c
@@ -554,7 +554,7 @@ ExecMakeFunctionResultSet(SetExprState *fcache,
 		fcache->funcResultStore = NULL;
 		*isDone = ExprEndResult;
 		*isNull = true;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 
 	/*
@@ -631,7 +631,7 @@ ExecMakeFunctionResultSet(SetExprState *fcache,
 	else
 	{
 		/* for a strict SRF, result for NULL is an empty set */
-		result = (Datum) 0;
+		result = DummyDatum;
 		*isNull = true;
 		*isDone = ExprEndResult;
 	}
@@ -677,7 +677,7 @@ ExecMakeFunctionResultSet(SetExprState *fcache,
 		/* if setResult was left null, treat it as empty set */
 		*isDone = ExprEndResult;
 		*isNull = true;
-		result = (Datum) 0;
+		result = DummyDatum;
 	}
 	else
 		ereport(ERROR,
diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c
index 8e02d68824f..78b4f741a9c 100644
--- a/src/backend/executor/execTuples.c
+++ b/src/backend/executor/execTuples.c
@@ -146,7 +146,7 @@ tts_virtual_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			 errmsg("cannot retrieve a system column in this context")));
 
-	return 0;					/* silence compiler warnings */
+	return DummyDatum;					/* silence compiler warnings */
 }
 
 /*
@@ -563,7 +563,7 @@ tts_minimal_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			 errmsg("cannot retrieve a system column in this context")));
 
-	return 0;					/* silence compiler warnings */
+	return DummyDatum;					/* silence compiler warnings */
 }
 
 /*
@@ -1036,7 +1036,7 @@ slot_deform_heap_tuple_internal(TupleTableSlot *slot, HeapTuple tuple,
 
 		if (hasnulls && att_isnull(attnum, bp))
 		{
-			values[attnum] = (Datum) 0;
+			values[attnum] = DummyDatum;
 			isnull[attnum] = true;
 			if (!slow)
 			{
@@ -2354,7 +2354,7 @@ BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
 		else
 		{
 			/* Handle dropped attributes by setting to NULL */
-			dvalues[i] = (Datum) 0;
+			dvalues[i] = DummyDatum;
 			nulls[i] = true;
 		}
 	}
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index fdc65c2b42b..f54f66ae5af 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -268,10 +268,10 @@ CreateExprContextInternal(EState *estate, Size minContextSize,
 	econtext->ecxt_aggvalues = NULL;
 	econtext->ecxt_aggnulls = NULL;
 
-	econtext->caseValue_datum = (Datum) 0;
+	econtext->caseValue_datum = DummyDatum;
 	econtext->caseValue_isNull = true;
 
-	econtext->domainValue_datum = (Datum) 0;
+	econtext->domainValue_datum = DummyDatum;
 	econtext->domainValue_isNull = true;
 
 	econtext->ecxt_estate = estate;
@@ -382,10 +382,10 @@ CreateStandaloneExprContext(void)
 	econtext->ecxt_aggvalues = NULL;
 	econtext->ecxt_aggnulls = NULL;
 
-	econtext->caseValue_datum = (Datum) 0;
+	econtext->caseValue_datum = DummyDatum;
 	econtext->caseValue_isNull = true;
 
-	econtext->domainValue_datum = (Datum) 0;
+	econtext->domainValue_datum = DummyDatum;
 	econtext->domainValue_isNull = true;
 
 	econtext->ecxt_estate = NULL;
@@ -997,7 +997,7 @@ UnregisterExprContextCallback(ExprContext *econtext,
 
 	while ((ecxt_callback = *prev_callback) != NULL)
 	{
-		if (ecxt_callback->function == function && ecxt_callback->arg == arg)
+		if (ecxt_callback->function == function && ecxt_callback->arg.value == arg.value)
 		{
 			*prev_callback = ecxt_callback->next;
 			pfree(ecxt_callback);
@@ -1078,7 +1078,7 @@ GetAttributeByName(HeapTupleHeader tuple, const char *attname, bool *isNull)
 	{
 		/* Kinda bogus but compatible with old behavior... */
 		*isNull = true;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 
 	tupType = HeapTupleHeaderGetTypeId(tuple);
@@ -1141,7 +1141,7 @@ GetAttributeByNum(HeapTupleHeader tuple,
 	{
 		/* Kinda bogus but compatible with old behavior... */
 		*isNull = true;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 
 	tupType = HeapTupleHeaderGetTypeId(tuple);
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
index 359aafea681..0414316e796 100644
--- a/src/backend/executor/functions.c
+++ b/src/backend/executor/functions.c
@@ -1773,7 +1773,7 @@ fmgr_sql(PG_FUNCTION_ARGS)
 			rsi->isDone = ExprEndResult;
 
 			fcinfo->isnull = true;
-			result = (Datum) 0;
+			result = DummyDatum;
 
 			/* Deregister shutdown callback, if we made one */
 			if (fcache->shutdown_reg)
@@ -1804,7 +1804,7 @@ fmgr_sql(PG_FUNCTION_ARGS)
 				rsi->setDesc = CreateTupleDescCopy(fcache->junkFilter->jf_cleanTupType);
 
 			fcinfo->isnull = true;
-			result = (Datum) 0;
+			result = DummyDatum;
 
 			/* Deregister shutdown callback, if we made one */
 			if (fcache->shutdown_reg)
@@ -1830,7 +1830,7 @@ fmgr_sql(PG_FUNCTION_ARGS)
 			else
 			{
 				fcinfo->isnull = true;
-				result = (Datum) 0;
+				result = DummyDatum;
 			}
 		}
 		else
@@ -1838,7 +1838,7 @@ fmgr_sql(PG_FUNCTION_ARGS)
 			/* Should only get here for VOID functions and procedures */
 			Assert(fcache->func->rettype == VOIDOID);
 			fcinfo->isnull = true;
-			result = (Datum) 0;
+			result = DummyDatum;
 		}
 	}
 
@@ -2347,7 +2347,7 @@ check_sql_stmt_retval(List *queryTreeList,
 												   -1,
 												   InvalidOid,
 												   sizeof(int32),
-												   (Datum) 0,
+												   DummyDatum,
 												   true,	/* isnull */
 												   true /* byval */ );
 					upper_tlist = lappend(upper_tlist,
@@ -2393,7 +2393,7 @@ check_sql_stmt_retval(List *queryTreeList,
 											   -1,
 											   InvalidOid,
 											   sizeof(int32),
-											   (Datum) 0,
+											   DummyDatum,
 											   true,	/* isnull */
 											   true /* byval */ );
 				upper_tlist = lappend(upper_tlist,
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index 377e016d732..6f86d9f1c16 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -848,14 +848,14 @@ process_ordered_aggregate_single(AggState *aggstate,
 								 AggStatePerTrans pertrans,
 								 AggStatePerGroup pergroupstate)
 {
-	Datum		oldVal = (Datum) 0;
+	Datum		oldVal = DummyDatum;
 	bool		oldIsNull = true;
 	bool		haveOldVal = false;
 	MemoryContext workcontext = aggstate->tmpcontext->ecxt_per_tuple_memory;
 	MemoryContext oldContext;
 	bool		isDistinct = (pertrans->numDistinctCols > 0);
-	Datum		newAbbrevVal = (Datum) 0;
-	Datum		oldAbbrevVal = (Datum) 0;
+	Datum		newAbbrevVal = DummyDatum;
+	Datum		oldAbbrevVal = DummyDatum;
 	FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
 	Datum	   *newVal;
 	bool	   *isNull;
@@ -891,7 +891,7 @@ process_ordered_aggregate_single(AggState *aggstate,
 			haveOldVal &&
 			((oldIsNull && *isNull) ||
 			 (!oldIsNull && !*isNull &&
-			  oldAbbrevVal == newAbbrevVal &&
+			  oldAbbrevVal.value == newAbbrevVal.value &&
 			  DatumGetBool(FunctionCall2Coll(&pertrans->equalfnOne,
 											 pertrans->aggCollation,
 											 oldVal, *newVal)))))
@@ -955,8 +955,8 @@ process_ordered_aggregate_multi(AggState *aggstate,
 	TupleTableSlot *slot2 = pertrans->uniqslot;
 	int			numTransInputs = pertrans->numTransInputs;
 	int			numDistinctCols = pertrans->numDistinctCols;
-	Datum		newAbbrevVal = (Datum) 0;
-	Datum		oldAbbrevVal = (Datum) 0;
+	Datum		newAbbrevVal = DummyDatum;
+	Datum		oldAbbrevVal = DummyDatum;
 	bool		haveOldValue = false;
 	TupleTableSlot *save = aggstate->tmpcontext->ecxt_outertuple;
 	int			i;
@@ -977,7 +977,7 @@ process_ordered_aggregate_multi(AggState *aggstate,
 
 		if (numDistinctCols == 0 ||
 			!haveOldValue ||
-			newAbbrevVal != oldAbbrevVal ||
+			newAbbrevVal.value != oldAbbrevVal.value ||
 			!ExecQual(pertrans->equalfnMulti, tmpcontext))
 		{
 			/*
@@ -1100,7 +1100,7 @@ finalize_aggregate(AggState *aggstate,
 		/* Fill any remaining argument positions with nulls */
 		for (; i < numFinalArgs; i++)
 		{
-			fcinfo->args[i].value = (Datum) 0;
+			fcinfo->args[i].value = DummyDatum;
 			fcinfo->args[i].isnull = true;
 			anynull = true;
 		}
@@ -1108,7 +1108,7 @@ finalize_aggregate(AggState *aggstate,
 		if (fcinfo->flinfo->fn_strict && anynull)
 		{
 			/* don't call a strict function with NULL inputs */
-			*resultVal = (Datum) 0;
+			*resultVal = DummyDatum;
 			*resultIsNull = true;
 		}
 		else
@@ -1161,7 +1161,7 @@ finalize_partialaggregate(AggState *aggstate,
 		/* Don't call a strict serialization function with NULL input. */
 		if (pertrans->serialfn.fn_strict && pergroupstate->transValueIsNull)
 		{
-			*resultVal = (Datum) 0;
+			*resultVal = DummyDatum;
 			*resultIsNull = true;
 		}
 		else
@@ -1334,7 +1334,7 @@ finalize_aggregates(AggState *aggstate,
 					pfree(DatumGetPointer(pertrans->lastdatum));
 
 				pertrans->lastisnull = false;
-				pertrans->lastdatum = (Datum) 0;
+				pertrans->lastdatum = DummyDatum;
 			}
 			else
 				ExecClearTuple(pertrans->uniqslot);
@@ -3970,7 +3970,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
 										  Anum_pg_aggregate_agginitval,
 										  &initValueIsNull);
 			if (initValueIsNull)
-				initValue = (Datum) 0;
+				initValue = DummyDatum;
 			else
 				initValue = GetAggInitVal(textInitVal, aggtranstype);
 
diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c
index 644363582d9..f4b5ae4a53b 100644
--- a/src/backend/executor/nodeFunctionscan.c
+++ b/src/backend/executor/nodeFunctionscan.c
@@ -196,7 +196,7 @@ FunctionNext(FunctionScanState *node)
 			 */
 			for (i = 0; i < fs->colcount; i++)
 			{
-				scanslot->tts_values[att] = (Datum) 0;
+				scanslot->tts_values[att] = DummyDatum;
 				scanslot->tts_isnull[att] = true;
 				att++;
 			}
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 7fcaa37fe62..2d0abfe6820 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -479,7 +479,7 @@ reorderqueue_push(IndexScanState *node, TupleTableSlot *slot,
 										   node->iss_OrderByTypByVals[i],
 										   node->iss_OrderByTypLens[i]);
 		else
-			rt->orderbyvals[i] = (Datum) 0;
+			rt->orderbyvals[i] = DummyDatum;
 		rt->orderbynulls[i] = orderbynulls[i];
 	}
 	pairingheap_add(node->iss_ReorderQueue, &rt->ph_node);
@@ -1293,7 +1293,7 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
 				runtime_keys[n_runtime_keys].key_toastable =
 					TypeIsToastable(op_righttype);
 				n_runtime_keys++;
-				scanvalue = (Datum) 0;
+				scanvalue = DummyDatum;
 			}
 
 			/*
@@ -1417,7 +1417,7 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
 					runtime_keys[n_runtime_keys].key_toastable =
 						TypeIsToastable(op_righttype);
 					n_runtime_keys++;
-					scanvalue = (Datum) 0;
+					scanvalue = DummyDatum;
 				}
 
 				/*
@@ -1541,7 +1541,7 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
 					 */
 					runtime_keys[n_runtime_keys].key_toastable = true;
 					n_runtime_keys++;
-					scanvalue = (Datum) 0;
+					scanvalue = DummyDatum;
 				}
 			}
 			else
@@ -1552,7 +1552,7 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
 					ExecInitExpr(rightop, planstate);
 				/* the remaining fields were zeroed by palloc0 */
 				n_array_keys++;
-				scanvalue = (Datum) 0;
+				scanvalue = DummyDatum;
 			}
 
 			/*
@@ -1616,7 +1616,7 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
 								   InvalidOid,	/* no strategy subtype */
 								   InvalidOid,	/* no collation */
 								   InvalidOid,	/* no reg proc for this */
-								   (Datum) 0);	/* constant */
+								   DummyDatum);	/* constant */
 		}
 		else
 			elog(ERROR, "unsupported indexqual type: %d",
diff --git a/src/backend/executor/nodeProjectSet.c b/src/backend/executor/nodeProjectSet.c
index 880f39fb2ff..c3bb01566a9 100644
--- a/src/backend/executor/nodeProjectSet.c
+++ b/src/backend/executor/nodeProjectSet.c
@@ -170,7 +170,7 @@ ExecProjectSRF(ProjectSetState *node, bool continuing)
 			 * If we're continuing to project output rows from a source tuple,
 			 * return NULLs once the SRF has been exhausted.
 			 */
-			*result = (Datum) 0;
+			*result = DummyDatum;
 			*isnull = true;
 			hassrf = true;
 		}
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index f7f6fc2da0b..e8579e8ab6c 100644
--- a/src/backend/executor/nodeSubplan.c
+++ b/src/backend/executor/nodeSubplan.c
@@ -467,7 +467,7 @@ ExecScanSubPlan(SubPlanState *node,
 		if (subLinkType == EXPR_SUBLINK ||
 			subLinkType == ROWCOMPARE_SUBLINK)
 		{
-			result = (Datum) 0;
+			result = DummyDatum;
 			*isNull = true;
 		}
 		else if (subLinkType == MULTIEXPR_SUBLINK)
@@ -480,7 +480,7 @@ ExecScanSubPlan(SubPlanState *node,
 
 				prmdata = &(econtext->ecxt_param_exec_vals[paramid]);
 				Assert(prmdata->execPlan == NULL);
-				prmdata->value = (Datum) 0;
+				prmdata->value = DummyDatum;
 				prmdata->isnull = true;
 			}
 		}
@@ -1219,7 +1219,7 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
 		 * to avoid leaking memory across repeated calls, we have to remember
 		 * the latest value, much as for curTuple above.
 		 */
-		if (node->curArray != PointerGetDatum(NULL))
+		if (DatumGetPointer(node->curArray) != NULL)
 			pfree(DatumGetPointer(node->curArray));
 		node->curArray = makeArrayResultAny(astate,
 											econtext->ecxt_per_query_memory,
@@ -1249,7 +1249,7 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
 				ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
 
 				prm->execPlan = NULL;
-				prm->value = (Datum) 0;
+				prm->value = DummyDatum;
 				prm->isnull = true;
 			}
 		}
diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c
index 9a1acce2b5d..fd4805806fb 100644
--- a/src/backend/executor/nodeWindowAgg.c
+++ b/src/backend/executor/nodeWindowAgg.c
@@ -230,7 +230,7 @@ initialize_windowaggregate(WindowAggState *winstate,
 	}
 	peraggstate->transValueIsNull = peraggstate->initValueIsNull;
 	peraggstate->transValueCount = 0;
-	peraggstate->resultValue = (Datum) 0;
+	peraggstate->resultValue = DummyDatum;
 	peraggstate->resultValueIsNull = true;
 }
 
@@ -612,7 +612,7 @@ finalize_windowaggregate(WindowAggState *winstate,
 		/* Fill any remaining argument positions with nulls */
 		for (i = 1; i < numFinalArgs; i++)
 		{
-			fcinfo->args[i].value = (Datum) 0;
+			fcinfo->args[i].value = DummyDatum;
 			fcinfo->args[i].isnull = true;
 			anynull = true;
 		}
@@ -620,7 +620,7 @@ finalize_windowaggregate(WindowAggState *winstate,
 		if (fcinfo->flinfo->fn_strict && anynull)
 		{
 			/* don't call a strict function with NULL inputs */
-			*result = (Datum) 0;
+			*result = DummyDatum;
 			*isnull = true;
 		}
 		else
@@ -896,7 +896,7 @@ eval_windowaggregates(WindowAggState *winstate)
 		{
 			if (!peraggstate->resulttypeByVal)
 				pfree(DatumGetPointer(peraggstate->resultValue));
-			peraggstate->resultValue = (Datum) 0;
+			peraggstate->resultValue = DummyDatum;
 			peraggstate->resultValueIsNull = true;
 		}
 	}
@@ -2366,7 +2366,7 @@ ExecWindowAgg(PlanState *pstate)
 					numfuncs = winstate->numfuncs;
 					for (i = 0; i < numfuncs; i++)
 					{
-						econtext->ecxt_aggvalues[i] = (Datum) 0;
+						econtext->ecxt_aggvalues[i] = DummyDatum;
 						econtext->ecxt_aggnulls[i] = true;
 					}
 
@@ -3020,7 +3020,7 @@ initialize_peragg(WindowAggState *winstate, WindowFunc *wfunc,
 								  &peraggstate->initValueIsNull);
 
 	if (peraggstate->initValueIsNull)
-		peraggstate->initValue = (Datum) 0;
+		peraggstate->initValue = DummyDatum;
 	else
 		peraggstate->initValue = GetAggInitVal(textInitVal,
 											   aggtranstype);
@@ -3413,7 +3413,7 @@ WinGetFuncArgInPartition(WindowObject winobj, int argno,
 		if (isout)
 			*isout = true;
 		*isnull = true;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 	else
 	{
@@ -3639,7 +3639,7 @@ WinGetFuncArgInFrame(WindowObject winobj, int argno,
 	if (isout)
 		*isout = true;
 	*isnull = true;
-	return (Datum) 0;
+	return DummyDatum;
 }
 
 /*
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index ecb2e4ccaa1..098e6aa3ac9 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -1258,7 +1258,7 @@ SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull)
 	{
 		SPI_result = SPI_ERROR_NOATTRIBUTE;
 		*isnull = true;
-		return (Datum) NULL;
+		return DummyDatum;
 	}
 
 	return heap_getattr(tuple, fnumber, tupdesc, isnull);
diff --git a/src/backend/foreign/foreign.c b/src/backend/foreign/foreign.c
index a57e59f27ea..d0853a91ed8 100644
--- a/src/backend/foreign/foreign.c
+++ b/src/backend/foreign/foreign.c
@@ -548,14 +548,14 @@ pg_options_to_table(PG_FUNCTION_ARGS)
 		}
 		else
 		{
-			values[1] = (Datum) 0;
+			values[1] = DummyDatum;
 			nulls[1] = true;
 		}
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
 							 values, nulls);
 	}
 
-	return (Datum) 0;
+	return DummyDatum;
 }
 
 
diff --git a/src/backend/jit/llvm/llvmjit.c b/src/backend/jit/llvm/llvmjit.c
index 46511624f01..ec2a536e820 100644
--- a/src/backend/jit/llvm/llvmjit.c
+++ b/src/backend/jit/llvm/llvmjit.c
@@ -900,7 +900,7 @@ llvm_session_initialize(void)
 		opt3_tm = 0;
 	}
 
-	on_proc_exit(llvm_shutdown, 0);
+	on_proc_exit(llvm_shutdown, DummyDatum);
 
 	llvm_session_initialized = true;
 
diff --git a/src/backend/jit/llvm/llvmjit_expr.c b/src/backend/jit/llvm/llvmjit_expr.c
index 890bcb0b0a7..b481be14482 100644
--- a/src/backend/jit/llvm/llvmjit_expr.c
+++ b/src/backend/jit/llvm/llvmjit_expr.c
@@ -650,7 +650,7 @@ llvm_compile_expr(ExprState *state)
 					LLVMValueRef v_constvalue,
 								v_constnull;
 
-					v_constvalue = l_sizet_const(op->d.constval.value);
+					v_constvalue = l_sizet_const(op->d.constval.value.value);
 					v_constnull = l_sbool_const(op->d.constval.isnull);
 
 					LLVMBuildStore(b, v_constvalue, v_resvaluep);
@@ -2014,7 +2014,7 @@ llvm_compile_expr(ExprState *state)
 				{
 					LLVMValueRef v_initvalue;
 
-					v_initvalue = l_sizet_const(op->d.hashdatum_initvalue.init_value);
+					v_initvalue = l_sizet_const(op->d.hashdatum_initvalue.init_value.value);
 
 					LLVMBuildStore(b, v_initvalue, v_resvaluep);
 					LLVMBuildStore(b, l_sbool_const(0), v_resnullp);
diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c
index e5171467de1..b6f1aceb2ad 100644
--- a/src/backend/libpq/pqcomm.c
+++ b/src/backend/libpq/pqcomm.c
@@ -283,7 +283,7 @@ pq_init(ClientSocket *client_sock)
 	PqCommReadingMsg = false;
 
 	/* set up process-exit hook to close the socket */
-	on_proc_exit(socket_close, 0);
+	on_proc_exit(socket_close, DummyDatum);
 
 	/*
 	 * In backends (as soon as forked) we operate the underlying socket in
diff --git a/src/backend/libpq/pqmq.c b/src/backend/libpq/pqmq.c
index f1a08bc32ca..87baceb4397 100644
--- a/src/backend/libpq/pqmq.c
+++ b/src/backend/libpq/pqmq.c
@@ -56,7 +56,7 @@ pq_redirect_to_shm_mq(dsm_segment *seg, shm_mq_handle *mqh)
 	pq_mq_handle = mqh;
 	whereToSendOutput = DestRemote;
 	FrontendProtocol = PG_PROTOCOL_LATEST;
-	on_dsm_detach(seg, pq_cleanup_redirect_to_shm_mq, (Datum) 0);
+	on_dsm_detach(seg, pq_cleanup_redirect_to_shm_mq, DummyDatum);
 }
 
 /*
diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c
index e2d9e9be41a..8663c37ed95 100644
--- a/src/backend/nodes/makefuncs.c
+++ b/src/backend/nodes/makefuncs.c
@@ -395,7 +395,7 @@ makeNullConst(Oid consttype, int32 consttypmod, Oid constcollid)
 					 consttypmod,
 					 constcollid,
 					 (int) typLen,
-					 (Datum) 0,
+					 DummyDatum,
 					 true,
 					 typByVal);
 }
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 48b5d13b9b6..b781c16256e 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -621,7 +621,7 @@ readDatum(bool typbyval)
 	{
 		if (length > (Size) sizeof(Datum))
 			elog(ERROR, "byval datum but length = %zu", length);
-		res = (Datum) 0;
+		res = DummyDatum;
 		s = (char *) (&res);
 		for (i = 0; i < (Size) sizeof(Datum); i++)
 		{
@@ -630,7 +630,7 @@ readDatum(bool typbyval)
 		}
 	}
 	else if (length <= 0)
-		res = (Datum) NULL;
+		res = DummyDatum;
 	else
 	{
 		s = (char *) palloc(length);
diff --git a/src/backend/optimizer/prep/prepagg.c b/src/backend/optimizer/prep/prepagg.c
index c0a2f04a8c3..8068ecf8938 100644
--- a/src/backend/optimizer/prep/prepagg.c
+++ b/src/backend/optimizer/prep/prepagg.c
@@ -209,7 +209,7 @@ preprocess_aggref(Aggref *aggref, PlannerInfo *root)
 								  Anum_pg_aggregate_agginitval,
 								  &initValueIsNull);
 	if (initValueIsNull)
-		initValue = (Datum) 0;
+		initValue = DummyDatum;
 	else
 		initValue = GetAggInitVal(textInitVal, aggtranstype);
 
diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c
index ffc9d6c3f30..71264165bc5 100644
--- a/src/backend/optimizer/prep/preptlist.c
+++ b/src/backend/optimizer/prep/preptlist.c
@@ -448,7 +448,7 @@ expand_insert_targetlist(PlannerInfo *root, List *tlist, Relation rel)
 											  -1,
 											  InvalidOid,
 											  sizeof(int32),
-											  (Datum) 0,
+											  DummyDatum,
 											  true, /* isnull */
 											  true /* byval */ );
 			}
@@ -463,7 +463,7 @@ expand_insert_targetlist(PlannerInfo *root, List *tlist, Relation rel)
 											  baseTypeMod,
 											  att_tup->attcollation,
 											  att_tup->attlen,
-											  (Datum) 0,
+											  DummyDatum,
 											  true, /* isnull */
 											  att_tup->attbyval);
 			}
diff --git a/src/backend/optimizer/util/predtest.c b/src/backend/optimizer/util/predtest.c
index ac28573cd0a..5caea86f576 100644
--- a/src/backend/optimizer/util/predtest.c
+++ b/src/backend/optimizer/util/predtest.c
@@ -2127,7 +2127,7 @@ lookup_proof_cache(Oid pred_op, Oid clause_op, bool refute_it)
 		/* Arrange to flush cache on pg_amop changes */
 		CacheRegisterSyscacheCallback(AMOPOPID,
 									  InvalidateOprProofCacheCallBack,
-									  (Datum) 0);
+									  DummyDatum);
 	}
 
 	key.pred_op = pred_op;
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index 0b5b81c7f27..acac11f1e9b 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -1284,7 +1284,7 @@ coerce_null_to_domain(Oid typid, int32 typmod, Oid collation,
 								baseTypeMod,
 								collation,
 								typlen,
-								(Datum) 0,
+								DummyDatum,
 								true,	/* isnull */
 								typbyval);
 	if (typid != baseTypeId)
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index d66276801c6..a74f8293bf5 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -4846,7 +4846,7 @@ transformJsonBehavior(ParseState *pstate, JsonBehavior *behavior,
 static Node *
 GetJsonBehaviorConst(JsonBehaviorType btype, int location)
 {
-	Datum		val = (Datum) 0;
+	Datum		val = DummyDatum;
 	Oid			typid = JSONBOID;
 	int			len = -1;
 	bool		isbyval = false;
@@ -4880,7 +4880,7 @@ GetJsonBehaviorConst(JsonBehaviorType btype, int location)
 		case JSON_BEHAVIOR_NULL:
 		case JSON_BEHAVIOR_UNKNOWN:
 		case JSON_BEHAVIOR_EMPTY:
-			val = (Datum) 0;
+			val = DummyDatum;
 			isnull = true;
 			typid = INT4OID;
 			len = sizeof(int32);
diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c
index d6feb16aef3..352285396bd 100644
--- a/src/backend/parser/parse_node.c
+++ b/src/backend/parser/parse_node.c
@@ -360,7 +360,7 @@ make_const(ParseState *pstate, A_Const *aconst)
 						-1,
 						InvalidOid,
 						-2,
-						(Datum) 0,
+						DummyDatum,
 						true,
 						false);
 		con->location = aconst->location;
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c
index 0c4337563cf..15536a772f5 100644
--- a/src/backend/parser/parse_oper.c
+++ b/src/backend/parser/parse_oper.c
@@ -995,10 +995,10 @@ find_oper_cache_entry(OprCacheKey *key)
 		/* Arrange to flush cache on pg_operator and pg_cast changes */
 		CacheRegisterSyscacheCallback(OPERNAMENSP,
 									  InvalidateOprCacheCallBack,
-									  (Datum) 0);
+									  DummyDatum);
 		CacheRegisterSyscacheCallback(CASTSOURCETARGET,
 									  InvalidateOprCacheCallBack,
-									  (Datum) 0);
+									  DummyDatum);
 	}
 
 	/* Look for an existing entry */
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index afcf54169c3..9fca9e23bf8 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -2549,7 +2549,7 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
 											   index_rel->rd_rel->relam);
 				if (indclass->values[i] != defopclass ||
 					attform->attcollation != index_rel->rd_indcollation[i] ||
-					attoptions != (Datum) 0 ||
+					attoptions.value != DummyDatum.value ||
 					index_rel->rd_indoption[i] != 0)
 					ereport(ERROR,
 							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
diff --git a/src/backend/partitioning/partbounds.c b/src/backend/partitioning/partbounds.c
index 4bdc2941efb..801356097f9 100644
--- a/src/backend/partitioning/partbounds.c
+++ b/src/backend/partitioning/partbounds.c
@@ -940,8 +940,8 @@ partition_bounds_equal(int partnatts, int16 *parttyplen, bool *parttypbyval,
 		 */
 #ifdef USE_ASSERT_CHECKING
 		for (i = 0; i < b1->ndatums; i++)
-			Assert((b1->datums[i][0] == b2->datums[i][0] &&
-					b1->datums[i][1] == b2->datums[i][1]));
+			Assert((b1->datums[i][0].value == b2->datums[i][0].value &&
+					b1->datums[i][1].value == b2->datums[i][1].value));
 #endif
 	}
 	else
diff --git a/src/backend/port/posix_sema.c b/src/backend/port/posix_sema.c
index 269c7460817..7b3c78ab254 100644
--- a/src/backend/port/posix_sema.c
+++ b/src/backend/port/posix_sema.c
@@ -227,7 +227,7 @@ PGReserveSemaphores(int maxSemas)
 	maxSems = maxSemas;
 	nextSemKey = statbuf.st_ino;
 
-	on_shmem_exit(ReleaseSemaphores, 0);
+	on_shmem_exit(ReleaseSemaphores, DummyDatum);
 }
 
 /*
diff --git a/src/backend/port/sysv_sema.c b/src/backend/port/sysv_sema.c
index 423b2b4f9d6..f6b16b55ab6 100644
--- a/src/backend/port/sysv_sema.c
+++ b/src/backend/port/sysv_sema.c
@@ -341,7 +341,7 @@ PGReserveSemaphores(int maxSemas)
 	nextSemaKey = statbuf.st_ino;
 	nextSemaNumber = SEMAS_PER_SET; /* force sema set alloc on 1st call */
 
-	on_shmem_exit(ReleaseSemaphores, 0);
+	on_shmem_exit(ReleaseSemaphores, DummyDatum);
 }
 
 /*
diff --git a/src/backend/port/sysv_shmem.c b/src/backend/port/sysv_shmem.c
index 197926d44f6..6c856efa60f 100644
--- a/src/backend/port/sysv_shmem.c
+++ b/src/backend/port/sysv_shmem.c
@@ -740,7 +740,7 @@ PGSharedMemoryCreate(Size size,
 		AnonymousShmemSize = size;
 
 		/* Register on-exit routine to unmap the anonymous segment */
-		on_shmem_exit(AnonymousShmemDetach, (Datum) 0);
+		on_shmem_exit(AnonymousShmemDetach, DummyDatum);
 
 		/* Now we need only allocate a minimal-sized SysV shmem block. */
 		sysvsize = sizeof(PGShmemHeader);
diff --git a/src/backend/port/win32_sema.c b/src/backend/port/win32_sema.c
index 5854ad1f54d..4ef1e469a75 100644
--- a/src/backend/port/win32_sema.c
+++ b/src/backend/port/win32_sema.c
@@ -52,7 +52,7 @@ PGReserveSemaphores(int maxSemas)
 	numSems = 0;
 	maxSems = maxSemas;
 
-	on_shmem_exit(ReleaseSemaphores, 0);
+	on_shmem_exit(ReleaseSemaphores, DummyDatum);
 }
 
 /*
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 9474095f271..97cd24c6106 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -1537,7 +1537,7 @@ AutoVacWorkerMain(const void *startup_data, size_t startup_data_len)
 		AutoVacuumShmem->av_startingWorker = NULL;
 		LWLockRelease(AutovacuumLock);
 
-		on_shmem_exit(FreeWorkerInfo, 0);
+		on_shmem_exit(FreeWorkerInfo, DummyDatum);
 
 		/* wake up the launcher */
 		if (AutoVacuumShmem->av_launcherpid != 0)
diff --git a/src/backend/postmaster/auxprocess.c b/src/backend/postmaster/auxprocess.c
index a6d3630398f..22b84b21b3d 100644
--- a/src/backend/postmaster/auxprocess.c
+++ b/src/backend/postmaster/auxprocess.c
@@ -82,7 +82,7 @@ AuxiliaryProcessMainCommon(void)
 	pgstat_bestart_final();
 
 	/* register a before-shutdown callback for LWLock cleanup */
-	before_shmem_exit(ShutdownAuxiliaryProcess, 0);
+	before_shmem_exit(ShutdownAuxiliaryProcess, DummyDatum);
 
 	SetProcessingMode(NormalProcessing);
 }
diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c
index 8490148a47d..2c1b951ceb3 100644
--- a/src/backend/postmaster/checkpointer.c
+++ b/src/backend/postmaster/checkpointer.c
@@ -242,7 +242,7 @@ CheckpointerMain(const void *startup_data, size_t startup_data_len)
 	 * signal checkpointer to exit after all processes that could emit stats
 	 * have been shut down.
 	 */
-	before_shmem_exit(pgstat_before_server_shutdown, 0);
+	before_shmem_exit(pgstat_before_server_shutdown, DummyDatum);
 
 	/*
 	 * Create a memory context that we will do all our work in.  We do this so
@@ -612,7 +612,7 @@ CheckpointerMain(const void *startup_data, size_t startup_data_len)
 		 * out pending statistic.
 		 */
 		PendingCheckpointerStats.num_requested++;
-		ShutdownXLOG(0, 0);
+		ShutdownXLOG(0, DummyDatum);
 		pgstat_report_checkpointer();
 		pgstat_report_wal(true);
 
diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c
index 78e39e5f866..105fedabb62 100644
--- a/src/backend/postmaster/pgarch.c
+++ b/src/backend/postmaster/pgarch.c
@@ -245,7 +245,7 @@ PgArchiverMain(const void *startup_data, size_t startup_data_len)
 	Assert(XLogArchivingActive());
 
 	/* Arrange to clean up at archiver exit */
-	on_shmem_exit(pgarch_die, 0);
+	on_shmem_exit(pgarch_die, DummyDatum);
 
 	/*
 	 * Advertise our proc number so that backends can use our latch to wake us
@@ -945,7 +945,7 @@ LoadArchiveLibrary(void)
 	if (ArchiveCallbacks->startup_cb != NULL)
 		ArchiveCallbacks->startup_cb(archive_module_state);
 
-	before_shmem_exit(pgarch_call_module_shutdown_cb, 0);
+	before_shmem_exit(pgarch_call_module_shutdown_cb, DummyDatum);
 }
 
 /*
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index e01d9f0cfe8..98240a99fc1 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -1109,7 +1109,7 @@ PostmasterMain(int argc, char *argv[])
 	 * sockets again at postmaster shutdown.
 	 */
 	ListenSockets = palloc(MAXLISTEN * sizeof(pgsocket));
-	on_proc_exit(CloseServerPorts, 0);
+	on_proc_exit(CloseServerPorts, DummyDatum);
 
 	if (ListenAddresses)
 	{
@@ -1308,7 +1308,7 @@ PostmasterMain(int argc, char *argv[])
 			write_stderr("%s: could not write external PID file \"%s\": %m\n",
 						 progname, external_pid_file);
 
-		on_proc_exit(unlink_external_pid_file, 0);
+		on_proc_exit(unlink_external_pid_file, DummyDatum);
 	}
 
 	/*
diff --git a/src/backend/postmaster/startup.c b/src/backend/postmaster/startup.c
index 27e86cf393f..1df0ff6711e 100644
--- a/src/backend/postmaster/startup.c
+++ b/src/backend/postmaster/startup.c
@@ -221,7 +221,7 @@ StartupProcessMain(const void *startup_data, size_t startup_data_len)
 	AuxiliaryProcessMainCommon();
 
 	/* Arrange to clean up at startup process exit */
-	on_shmem_exit(StartupProcExit, 0);
+	on_shmem_exit(StartupProcExit, DummyDatum);
 
 	/*
 	 * Properly accept or ignore signals the postmaster might send us.
diff --git a/src/backend/postmaster/walsummarizer.c b/src/backend/postmaster/walsummarizer.c
index 777c9a8d555..386a23eecb3 100644
--- a/src/backend/postmaster/walsummarizer.c
+++ b/src/backend/postmaster/walsummarizer.c
@@ -256,7 +256,7 @@ WalSummarizerMain(const void *startup_data, size_t startup_data_len)
 	pqsignal(SIGUSR2, SIG_IGN); /* not used */
 
 	/* Advertise ourselves. */
-	on_shmem_exit(WalSummarizerShutdown, (Datum) 0);
+	on_shmem_exit(WalSummarizerShutdown, DummyDatum);
 	LWLockAcquire(WALSummarizerLock, LW_EXCLUSIVE);
 	WalSummarizerCtl->summarizer_pgprocno = MyProcNumber;
 	LWLockRelease(WALSummarizerLock);
diff --git a/src/backend/replication/logical/applyparallelworker.c b/src/backend/replication/logical/applyparallelworker.c
index 1fa931a7422..6c40a466744 100644
--- a/src/backend/replication/logical/applyparallelworker.c
+++ b/src/backend/replication/logical/applyparallelworker.c
@@ -964,7 +964,7 @@ ParallelApplyWorkerMain(Datum main_arg)
 	 */
 	CacheRegisterSyscacheCallback(SUBSCRIPTIONRELMAP,
 								  invalidate_syncing_table_states,
-								  (Datum) 0);
+								  DummyDatum);
 
 	set_apply_error_context_origin(originname);
 
diff --git a/src/backend/replication/logical/launcher.c b/src/backend/replication/logical/launcher.c
index 742d9ba68e9..a6223d25b70 100644
--- a/src/backend/replication/logical/launcher.c
+++ b/src/backend/replication/logical/launcher.c
@@ -752,7 +752,7 @@ logicalrep_worker_attach(int slot)
 	}
 
 	MyLogicalRepWorker->proc = MyProc;
-	before_shmem_exit(logicalrep_worker_onexit, (Datum) 0);
+	before_shmem_exit(logicalrep_worker_onexit, DummyDatum);
 
 	LWLockRelease(LogicalRepWorkerLock);
 }
@@ -962,7 +962,7 @@ ApplyLauncherRegister(void)
 			 "logical replication launcher");
 	bgw.bgw_restart_time = 5;
 	bgw.bgw_notify_pid = 0;
-	bgw.bgw_main_arg = (Datum) 0;
+	bgw.bgw_main_arg = DummyDatum;
 
 	RegisterBackgroundWorker(&bgw);
 }
@@ -1148,7 +1148,7 @@ ApplyLauncherMain(Datum main_arg)
 	ereport(DEBUG1,
 			(errmsg_internal("logical replication launcher started")));
 
-	before_shmem_exit(logicalrep_launcher_onexit, (Datum) 0);
+	before_shmem_exit(logicalrep_launcher_onexit, DummyDatum);
 
 	Assert(LogicalRepCtx->launcher_pid == 0);
 	LogicalRepCtx->launcher_pid = MyProcPid;
@@ -1606,5 +1606,5 @@ pg_stat_get_subscription(PG_FUNCTION_ARGS)
 
 	LWLockRelease(LogicalRepWorkerLock);
 
-	return (Datum) 0;
+	return DummyDatum;
 }
diff --git a/src/backend/replication/logical/logicalfuncs.c b/src/backend/replication/logical/logicalfuncs.c
index ca53caac2f2..9a6c382cc3b 100644
--- a/src/backend/replication/logical/logicalfuncs.c
+++ b/src/backend/replication/logical/logicalfuncs.c
@@ -321,7 +321,7 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin
 	}
 	PG_END_TRY();
 
-	return (Datum) 0;
+	return DummyDatum;
 }
 
 /*
diff --git a/src/backend/replication/logical/origin.c b/src/backend/replication/logical/origin.c
index 87f10e50dcc..064a5bce49e 100644
--- a/src/backend/replication/logical/origin.c
+++ b/src/backend/replication/logical/origin.c
@@ -1125,7 +1125,7 @@ replorigin_session_setup(RepOriginId node, int acquired_by)
 
 	if (!registered_cleanup)
 	{
-		on_shmem_exit(ReplicationOriginExitCleanup, 0);
+		on_shmem_exit(ReplicationOriginExitCleanup, DummyDatum);
 		registered_cleanup = true;
 	}
 
@@ -1603,5 +1603,5 @@ pg_show_replication_origin_status(PG_FUNCTION_ARGS)
 
 #undef REPLICATION_ORIGIN_PROGRESS_COLS
 
-	return (Datum) 0;
+	return DummyDatum;
 }
diff --git a/src/backend/replication/logical/relation.c b/src/backend/replication/logical/relation.c
index f59046ad620..4e2e2520136 100644
--- a/src/backend/replication/logical/relation.c
+++ b/src/backend/replication/logical/relation.c
@@ -122,7 +122,7 @@ logicalrep_relmap_init(void)
 
 	/* Watch for invalidation events. */
 	CacheRegisterRelcacheCallback(logicalrep_relmap_invalidate_cb,
-								  (Datum) 0);
+								  DummyDatum);
 }
 
 /*
@@ -615,7 +615,7 @@ logicalrep_partmap_init(void)
 
 	/* Watch for invalidation events. */
 	CacheRegisterRelcacheCallback(logicalrep_partmap_invalidate_cb,
-								  (Datum) 0);
+								  DummyDatum);
 }
 
 /*
diff --git a/src/backend/replication/logical/slotsync.c b/src/backend/replication/logical/slotsync.c
index 2f0c08b8fbd..93a51f50f31 100644
--- a/src/backend/replication/logical/slotsync.c
+++ b/src/backend/replication/logical/slotsync.c
@@ -1422,7 +1422,7 @@ ReplSlotSyncWorkerMain(const void *startup_data, size_t startup_data_len)
 	ereport(LOG, errmsg("slot sync worker started"));
 
 	/* Register it as soon as SlotSyncCtx->pid is initialized. */
-	before_shmem_exit(slotsync_worker_onexit, (Datum) 0);
+	before_shmem_exit(slotsync_worker_onexit, DummyDatum);
 
 	/*
 	 * Establishes SIGALRM handler and initialize timeout module. It is needed
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index b59221c4d06..74edd29821e 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -1040,7 +1040,7 @@ slot_store_data(TupleTableSlot *slot, LogicalRepRelMapEntry *rel,
 				 * LOGICALREP_COLUMN_UNCHANGED here, but if we do, treat it as
 				 * NULL.)
 				 */
-				slot->tts_values[i] = (Datum) 0;
+				slot->tts_values[i] = DummyDatum;
 				slot->tts_isnull[i] = true;
 			}
 
@@ -1054,7 +1054,7 @@ slot_store_data(TupleTableSlot *slot, LogicalRepRelMapEntry *rel,
 			 * (missing values should be later filled using
 			 * slot_fill_defaults).
 			 */
-			slot->tts_values[i] = (Datum) 0;
+			slot->tts_values[i] = DummyDatum;
 			slot->tts_isnull[i] = true;
 		}
 	}
@@ -1151,7 +1151,7 @@ slot_modify_data(TupleTableSlot *slot, TupleTableSlot *srcslot,
 			else
 			{
 				/* must be LOGICALREP_COLUMN_NULL */
-				slot->tts_values[i] = (Datum) 0;
+				slot->tts_values[i] = DummyDatum;
 				slot->tts_isnull[i] = true;
 			}
 
@@ -5106,7 +5106,7 @@ start_apply(XLogRecPtr origin_startpos)
 		 * transaction loss as that transaction won't be sent again by the
 		 * server.
 		 */
-		replorigin_reset(0, (Datum) 0);
+		replorigin_reset(0, DummyDatum);
 
 		if (MySubscription->disableonerr)
 			DisableSubscriptionAndExit();
@@ -5331,11 +5331,11 @@ InitializeLogRepWorker(void)
 	 */
 	CacheRegisterSyscacheCallback(SUBSCRIPTIONOID,
 								  subscription_change_cb,
-								  (Datum) 0);
+								  DummyDatum);
 
 	CacheRegisterSyscacheCallback(AUTHOID,
 								  subscription_change_cb,
-								  (Datum) 0);
+								  DummyDatum);
 
 	if (am_tablesync_worker())
 		ereport(LOG,
@@ -5400,7 +5400,7 @@ SetupApplyOrSyncWorker(int worker_slot)
 	 * state may process a shutdown signal before committing the current apply
 	 * operation. So, it is important to register such a callback here.
 	 */
-	before_shmem_exit(replorigin_reset, (Datum) 0);
+	before_shmem_exit(replorigin_reset, DummyDatum);
 
 	/* Connect to the origin and start the replication. */
 	elog(DEBUG1, "connecting to publisher using connection string \"%s\"",
@@ -5412,7 +5412,7 @@ SetupApplyOrSyncWorker(int worker_slot)
 	 */
 	CacheRegisterSyscacheCallback(SUBSCRIPTIONRELMAP,
 								  invalidate_syncing_table_states,
-								  (Datum) 0);
+								  DummyDatum);
 }
 
 /* Logical Replication Apply worker entry point */
diff --git a/src/backend/replication/pgoutput/pgoutput.c b/src/backend/replication/pgoutput/pgoutput.c
index 80540c017bd..69a90ff5e32 100644
--- a/src/backend/replication/pgoutput/pgoutput.c
+++ b/src/backend/replication/pgoutput/pgoutput.c
@@ -535,9 +535,9 @@ pgoutput_startup(LogicalDecodingContext *ctx, OutputPluginOptions *opt,
 		{
 			CacheRegisterSyscacheCallback(PUBLICATIONOID,
 										  publication_invalidation_cb,
-										  (Datum) 0);
+										  DummyDatum);
 			CacheRegisterRelSyncCallback(rel_sync_cache_relation_cb,
-										 (Datum) 0);
+										 DummyDatum);
 			publication_callback_registered = true;
 		}
 
@@ -918,7 +918,7 @@ pgoutput_row_filter_init(PGOutputData *data, List *publications,
 	{
 		Publication *pub = lfirst(lc);
 		HeapTuple	rftuple = NULL;
-		Datum		rfdatum = 0;
+		Datum		rfdatum = DummyDatum;
 		bool		pub_no_filter = true;
 
 		/*
@@ -1973,7 +1973,7 @@ init_rel_sync_cache(MemoryContext cachectx)
 		return;
 
 	/* We must update the cache entry for a relation after a relcache flush */
-	CacheRegisterRelcacheCallback(rel_sync_cache_relation_cb, (Datum) 0);
+	CacheRegisterRelcacheCallback(rel_sync_cache_relation_cb, DummyDatum);
 
 	/*
 	 * Flush all cache entries after a pg_namespace change, in case it was a
@@ -1988,7 +1988,7 @@ init_rel_sync_cache(MemoryContext cachectx)
 	 */
 	CacheRegisterSyscacheCallback(NAMESPACEOID,
 								  rel_sync_cache_publication_cb,
-								  (Datum) 0);
+								  DummyDatum);
 
 	relation_callbacks_registered = true;
 }
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index 8605776ad86..80a5b0efb2f 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -240,7 +240,7 @@ ReplicationSlotsShmemInit(void)
 void
 ReplicationSlotInitialize(void)
 {
-	before_shmem_exit(ReplicationSlotShmemExit, 0);
+	before_shmem_exit(ReplicationSlotShmemExit, DummyDatum);
 }
 
 /*
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 69f4c6157c5..f7668f47e55 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -451,7 +451,7 @@ pg_get_replication_slots(PG_FUNCTION_ARGS)
 
 	LWLockRelease(ReplicationSlotControlLock);
 
-	return (Datum) 0;
+	return DummyDatum;
 }
 
 /*
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index ee911394a23..29c8cbeca47 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -3054,7 +3054,7 @@ InitWalSenderSlot(void)
 	Assert(MyWalSnd != NULL);
 
 	/* Arrange to clean up at walsender exit */
-	on_shmem_exit(WalSndKill, 0);
+	on_shmem_exit(WalSndKill, DummyDatum);
 }
 
 /* Destroy the per-walsender data structure for this walsender process */
@@ -4113,7 +4113,7 @@ pg_stat_get_wal_senders(PG_FUNCTION_ARGS)
 							 values, nulls);
 	}
 
-	return (Datum) 0;
+	return DummyDatum;
 }
 
 /*
diff --git a/src/backend/statistics/attribute_stats.c b/src/backend/statistics/attribute_stats.c
index e8241926d2c..0905801e01d 100644
--- a/src/backend/statistics/attribute_stats.c
+++ b/src/backend/statistics/attribute_stats.c
@@ -404,7 +404,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo)
 			set_stats_slot(values, nulls, replaces,
 						   STATISTIC_KIND_HISTOGRAM,
 						   lt_opr, atttypcoll,
-						   0, true, stavalues, false);
+						   DummyDatum, true, stavalues, false);
 		}
 		else
 			result = false;
@@ -420,7 +420,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo)
 		set_stats_slot(values, nulls, replaces,
 					   STATISTIC_KIND_CORRELATION,
 					   lt_opr, atttypcoll,
-					   stanumbers, false, 0, true);
+					   stanumbers, false, DummyDatum, true);
 	}
 
 	/* STATISTIC_KIND_MCELEM */
@@ -455,7 +455,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo)
 		set_stats_slot(values, nulls, replaces,
 					   STATISTIC_KIND_DECHIST,
 					   elem_eq_opr, atttypcoll,
-					   stanumbers, false, 0, true);
+					   stanumbers, false, DummyDatum, true);
 	}
 
 	/*
@@ -481,7 +481,7 @@ attribute_statistics_update(FunctionCallInfo fcinfo)
 			set_stats_slot(values, nulls, replaces,
 						   STATISTIC_KIND_BOUNDS_HISTOGRAM,
 						   InvalidOid, InvalidOid,
-						   0, true, stavalues, false);
+						   DummyDatum, true, stavalues, false);
 		}
 		else
 			result = false;
@@ -722,7 +722,7 @@ text_to_stavalues(const char *staname, FmgrInfo *array_in, Datum d, Oid typid,
 		escontext.error_data->elevel = WARNING;
 		ThrowErrorData(escontext.error_data);
 		*ok = false;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 
 	if (array_contains_nulls(DatumGetArrayTypeP(result)))
@@ -731,7 +731,7 @@ text_to_stavalues(const char *staname, FmgrInfo *array_in, Datum d, Oid typid,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("\"%s\" array cannot contain NULL values", staname)));
 		*ok = false;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 
 	*ok = true;
@@ -893,7 +893,7 @@ init_empty_stats_tuple(Oid reloid, int16 attnum, bool inherited,
 	/* initialize stakind, staop, and stacoll slots */
 	for (int slotnum = 0; slotnum < STATISTIC_NUM_SLOTS; slotnum++)
 	{
-		values[Anum_pg_statistic_stakind1 + slotnum - 1] = (Datum) 0;
+		values[Anum_pg_statistic_stakind1 + slotnum - 1] = DummyDatum;
 		nulls[Anum_pg_statistic_stakind1 + slotnum - 1] = false;
 		values[Anum_pg_statistic_staop1 + slotnum - 1] = ObjectIdGetDatum(InvalidOid);
 		nulls[Anum_pg_statistic_staop1 + slotnum - 1] = false;
diff --git a/src/backend/statistics/extended_stats.c b/src/backend/statistics/extended_stats.c
index 3e031cf831a..90e6e1302eb 100644
--- a/src/backend/statistics/extended_stats.c
+++ b/src/backend/statistics/extended_stats.c
@@ -155,7 +155,7 @@ BuildRelationExtStatistics(Relation onerel, bool inh, double totalrows,
 		MVNDistinct *ndistinct = NULL;
 		MVDependencies *dependencies = NULL;
 		MCVList    *mcv = NULL;
-		Datum		exprstats = (Datum) 0;
+		Datum		exprstats = DummyDatum;
 		VacAttrStats **stats;
 		ListCell   *lc2;
 		int			stattarget;
@@ -803,7 +803,7 @@ statext_store(Oid statOid, bool inh,
 		nulls[Anum_pg_statistic_ext_data_stxdmcv - 1] = (data == NULL);
 		values[Anum_pg_statistic_ext_data_stxdmcv - 1] = PointerGetDatum(data);
 	}
-	if (exprs != (Datum) 0)
+	if (exprs.value != DummyDatum.value)
 	{
 		nulls[Anum_pg_statistic_ext_data_stxdexpr - 1] = false;
 		values[Anum_pg_statistic_ext_data_stxdexpr - 1] = exprs;
@@ -2180,7 +2180,7 @@ compute_expr_stats(Relation onerel, AnlExprData *exprdata, int nexprs,
 											  &isnull);
 			if (isnull)
 			{
-				exprvals[tcnt] = (Datum) 0;
+				exprvals[tcnt] = DummyDatum;
 				exprnulls[tcnt] = true;
 			}
 			else
@@ -2319,7 +2319,7 @@ serialize_expr_stats(AnlExprData *exprdata, int nexprs)
 		if (!stats->stats_valid)
 		{
 			astate = accumArrayResult(astate,
-									  (Datum) 0,
+									  DummyDatum,
 									  true,
 									  typOid,
 									  CurrentMemoryContext);
@@ -2374,7 +2374,7 @@ serialize_expr_stats(AnlExprData *exprdata, int nexprs)
 			else
 			{
 				nulls[i] = true;
-				values[i++] = (Datum) 0;
+				values[i++] = DummyDatum;
 			}
 		}
 		i = Anum_pg_statistic_stavalues1 - 1;
@@ -2395,7 +2395,7 @@ serialize_expr_stats(AnlExprData *exprdata, int nexprs)
 			else
 			{
 				nulls[i] = true;
-				values[i++] = (Datum) 0;
+				values[i++] = DummyDatum;
 			}
 		}
 
@@ -2613,7 +2613,7 @@ make_build_data(Relation rel, StatExtEntry *stat, int numrows, HeapTuple *rows,
 								 &isnull);
 			if (isnull)
 			{
-				result->values[idx][i] = (Datum) 0;
+				result->values[idx][i] = DummyDatum;
 				result->nulls[idx][i] = true;
 			}
 			else
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index f59fb821543..51d66870184 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1188,7 +1188,7 @@ statext_mcv_deserialize(bytea *data)
 			/* for by-val types we simply copy data into the mapping */
 			for (i = 0; i < info[dim].nvalues; i++)
 			{
-				Datum		v = 0;
+				Datum		v = DummyDatum;
 
 				memcpy(&v, ptr, info[dim].typlen);
 				ptr += info[dim].typlen;
@@ -1433,7 +1433,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 			}
 			else
 				astate_values = accumArrayResult(astate_values,
-												 (Datum) 0,
+												 DummyDatum,
 												 true,
 												 TEXTOID,
 												 CurrentMemoryContext);
diff --git a/src/backend/statistics/stat_utils.c b/src/backend/statistics/stat_utils.c
index a9a3224efe6..c0c24032cf3 100644
--- a/src/backend/statistics/stat_utils.c
+++ b/src/backend/statistics/stat_utils.c
@@ -295,7 +295,7 @@ stats_fill_fcinfo_from_arg_pairs(FunctionCallInfo pairs_fcinfo,
 	/* clear positional args */
 	for (int i = 0; arginfo[i].argname != NULL; i++)
 	{
-		positional_fcinfo->args[i].value = (Datum) 0;
+		positional_fcinfo->args[i].value = DummyDatum;
 		positional_fcinfo->args[i].isnull = true;
 	}
 
diff --git a/src/backend/storage/aio/aio_funcs.c b/src/backend/storage/aio/aio_funcs.c
index b25f9204041..7c80ee50d5a 100644
--- a/src/backend/storage/aio/aio_funcs.c
+++ b/src/backend/storage/aio/aio_funcs.c
@@ -226,5 +226,5 @@ pg_get_aios(PG_FUNCTION_ARGS)
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
 
-	return (Datum) 0;
+	return DummyDatum;
 }
diff --git a/src/backend/storage/aio/aio_init.c b/src/backend/storage/aio/aio_init.c
index 885c3940c66..7012105b13b 100644
--- a/src/backend/storage/aio/aio_init.c
+++ b/src/backend/storage/aio/aio_init.c
@@ -235,5 +235,5 @@ pgaio_init_backend(void)
 	if (pgaio_method_ops->init_backend)
 		pgaio_method_ops->init_backend();
 
-	before_shmem_exit(pgaio_shutdown, 0);
+	before_shmem_exit(pgaio_shutdown, DummyDatum);
 }
diff --git a/src/backend/storage/aio/method_worker.c b/src/backend/storage/aio/method_worker.c
index bf8f77e6ff6..0e90007c187 100644
--- a/src/backend/storage/aio/method_worker.c
+++ b/src/backend/storage/aio/method_worker.c
@@ -358,7 +358,7 @@ pgaio_worker_register(void)
 	io_worker_control->workers[MyIoWorkerId].latch = MyLatch;
 	LWLockRelease(AioWorkerSubmissionQueueLock);
 
-	on_shmem_exit(pgaio_worker_die, 0);
+	on_shmem_exit(pgaio_worker_die, DummyDatum);
 }
 
 static void
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index c50b4a2cd2f..61f4fffc0db 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -4033,7 +4033,7 @@ InitBufferManagerAccess(void)
 	 * the corresponding phase of backend shutdown.
 	 */
 	Assert(MyProc != NULL);
-	on_shmem_exit(AtProcExit_Buffers, 0);
+	on_shmem_exit(AtProcExit_Buffers, DummyDatum);
 }
 
 /*
diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c
index a4ec7959f31..70b1613e349 100644
--- a/src/backend/storage/file/fd.c
+++ b/src/backend/storage/file/fd.c
@@ -936,7 +936,7 @@ InitTemporaryFileAccess(void)
 	 * Register before-shmem-exit hook to ensure temp files are dropped while
 	 * we can still report stats.
 	 */
-	before_shmem_exit(BeforeShmemExit_Files, 0);
+	before_shmem_exit(BeforeShmemExit_Files, DummyDatum);
 
 #ifdef USE_ASSERT_CHECKING
 	temporary_files_allowed = true;
diff --git a/src/backend/storage/ipc/dsm.c b/src/backend/storage/ipc/dsm.c
index f92a52a00e6..e14476997f8 100644
--- a/src/backend/storage/ipc/dsm.c
+++ b/src/backend/storage/ipc/dsm.c
@@ -1154,7 +1154,7 @@ cancel_on_dsm_detach(dsm_segment *seg, on_dsm_detach_callback function,
 		dsm_segment_detach_callback *cb;
 
 		cb = slist_container(dsm_segment_detach_callback, node, iter.cur);
-		if (cb->function == function && cb->arg == arg)
+		if (cb->function == function && cb->arg.value == arg.value)
 		{
 			slist_delete_current(&iter);
 			pfree(cb);
diff --git a/src/backend/storage/ipc/dsm_registry.c b/src/backend/storage/ipc/dsm_registry.c
index 1682cc6d34c..afda1db9b5a 100644
--- a/src/backend/storage/ipc/dsm_registry.c
+++ b/src/backend/storage/ipc/dsm_registry.c
@@ -482,5 +482,5 @@ pg_get_dsm_registry_allocations(PG_FUNCTION_ARGS)
 	}
 	dshash_seq_term(&status);
 
-	return (Datum) 0;
+	return DummyDatum;
 }
diff --git a/src/backend/storage/ipc/ipc.c b/src/backend/storage/ipc/ipc.c
index 567739b5be9..69057ce2c49 100644
--- a/src/backend/storage/ipc/ipc.c
+++ b/src/backend/storage/ipc/ipc.c
@@ -396,11 +396,11 @@ cancel_before_shmem_exit(pg_on_exit_callback function, Datum arg)
 	if (before_shmem_exit_index > 0 &&
 		before_shmem_exit_list[before_shmem_exit_index - 1].function
 		== function &&
-		before_shmem_exit_list[before_shmem_exit_index - 1].arg == arg)
+		before_shmem_exit_list[before_shmem_exit_index - 1].arg.value == arg.value)
 		--before_shmem_exit_index;
 	else
 		elog(ERROR, "before_shmem_exit callback (%p,0x%" PRIxPTR ") is not the latest entry",
-			 function, arg);
+			 function, arg.value);
 }
 
 /* ----------------------------------------------------------------
diff --git a/src/backend/storage/ipc/pmsignal.c b/src/backend/storage/ipc/pmsignal.c
index f2ea01622f9..a78c5dbe18d 100644
--- a/src/backend/storage/ipc/pmsignal.c
+++ b/src/backend/storage/ipc/pmsignal.c
@@ -297,7 +297,7 @@ RegisterPostmasterChildActive(void)
 	PMSignalState->PMChildFlags[slot] = PM_CHILD_ACTIVE;
 
 	/* Arrange to clean up at exit. */
-	on_shmem_exit(MarkPostmasterChildInactive, 0);
+	on_shmem_exit(MarkPostmasterChildInactive, DummyDatum);
 }
 
 /*
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 087821311cc..7a76de115bc 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -216,7 +216,7 @@ ProcSignalInit(const uint8 *cancel_key, int cancel_key_len)
 	MyProcSignalSlot = slot;
 
 	/* Set up to release the slot on process exit */
-	on_shmem_exit(CleanupProcSignalState, (Datum) 0);
+	on_shmem_exit(CleanupProcSignalState, DummyDatum);
 }
 
 /*
diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c
index d12a3ca0684..69777b92951 100644
--- a/src/backend/storage/ipc/shmem.c
+++ b/src/backend/storage/ipc/shmem.c
@@ -571,7 +571,7 @@ pg_get_shmem_allocations(PG_FUNCTION_ARGS)
 
 	LWLockRelease(ShmemIndexLock);
 
-	return (Datum) 0;
+	return DummyDatum;
 }
 
 /*
@@ -725,7 +725,7 @@ pg_get_shmem_allocations_numa(PG_FUNCTION_ARGS)
 	LWLockRelease(ShmemIndexLock);
 	firstNumaTouch = false;
 
-	return (Datum) 0;
+	PG_RETURN_DUMMY();
 }
 
 /*
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index c07fb588355..cc35993aebc 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -292,6 +292,8 @@
 #define SxactIsROUnsafe(sxact) (((sxact)->flags & SXACT_FLAG_RO_UNSAFE) != 0)
 #define SxactIsPartiallyReleased(sxact) (((sxact)->flags & SXACT_FLAG_PARTIALLY_RELEASED) != 0)
 
+static HTAB *PredicateLockTargetHash; // XXX
+
 /*
  * Compute the hash code associated with a PREDICATELOCKTARGETTAG.
  *
@@ -300,8 +302,11 @@
  * passing the hashcode to hash_search_with_hash_value(), we can extract
  * the lock partition number from the hashcode.
  */
-#define PredicateLockTargetTagHashCode(predicatelocktargettag) \
-	get_hash_value(PredicateLockTargetHash, predicatelocktargettag)
+static inline uint32
+PredicateLockTargetTagHashCode(const PREDICATELOCKTARGETTAG *predicatelocktargettag)
+{
+	return get_hash_value(PredicateLockTargetHash, predicatelocktargettag);
+}
 
 /*
  * Given a predicate lock tag, and the hash for its target,
@@ -313,9 +318,12 @@
  * don't care if we lose high-order bits of the address; use an
  * intermediate variable to suppress cast-pointer-to-int warnings.
  */
-#define PredicateLockHashCodeFromTargetHashCode(predicatelocktag, targethash) \
-	((targethash) ^ ((uint32) PointerGetDatum((predicatelocktag)->myXact)) \
-	 << LOG2_NUM_PREDICATELOCK_PARTITIONS)
+static inline uint32
+PredicateLockHashCodeFromTargetHashCode(const PREDICATELOCKTAG *predicatelocktag, uint32 targethash)
+{
+	return (targethash ^ DatumGetUInt32(PointerGetDatum(predicatelocktag->myXact))
+			<< LOG2_NUM_PREDICATELOCK_PARTITIONS);
+}
 
 
 /*
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index e9ef0fbfe32..5e8cbdfc70d 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -549,7 +549,7 @@ InitProcess(void)
 	/*
 	 * Arrange to clean up at backend exit.
 	 */
-	on_shmem_exit(ProcKill, 0);
+	on_shmem_exit(ProcKill, DummyDatum);
 
 	/*
 	 * Now that we have a PGPROC, we could try to acquire locks, so initialize
@@ -589,7 +589,7 @@ InitProcessPhase2(void)
 	/*
 	 * Arrange to clean that up at backend exit.
 	 */
-	on_shmem_exit(RemoveProcFromArray, 0);
+	on_shmem_exit(RemoveProcFromArray, DummyDatum);
 }
 
 /*
diff --git a/src/backend/storage/smgr/smgr.c b/src/backend/storage/smgr/smgr.c
index bce37a36d51..007e9cd2417 100644
--- a/src/backend/storage/smgr/smgr.c
+++ b/src/backend/storage/smgr/smgr.c
@@ -200,7 +200,7 @@ smgrinit(void)
 	RESUME_INTERRUPTS();
 
 	/* register the shutdown proc */
-	on_proc_exit(smgrshutdown, 0);
+	on_proc_exit(smgrshutdown, DummyDatum); // XXX change to void * instead??
 }
 
 /*
diff --git a/src/backend/tcop/fastpath.c b/src/backend/tcop/fastpath.c
index 62f9ffa0dc0..ba6eca0d489 100644
--- a/src/backend/tcop/fastpath.c
+++ b/src/backend/tcop/fastpath.c
@@ -291,7 +291,7 @@ HandleFunctionRequest(StringInfo msgBuf)
 	else
 	{
 		fcinfo->isnull = true;
-		retval = (Datum) 0;
+		retval = DummyDatum;
 	}
 
 	/* ensure we do at least one CHECK_FOR_INTERRUPTS per function call */
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 0cecd464902..96a51cca96b 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -1950,7 +1950,7 @@ exec_bind_message(StringInfo input_message)
 						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 						 errmsg("unsupported format code: %d",
 								pformat)));
-				pval = 0;		/* keep compiler quiet */
+				pval = DummyDatum;		/* keep compiler quiet */
 			}
 
 			/* Restore message buffer contents */
@@ -4315,7 +4315,7 @@ PostgresMain(const char *dbname, const char *username)
 	 * sure Log_disconnections has its final value.
 	 */
 	if (IsUnderPostmaster && Log_disconnections)
-		on_proc_exit(log_disconnections, 0);
+		on_proc_exit(log_disconnections, DummyDatum);
 
 	pgstat_report_connect(MyDatabaseId);
 
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 4f4191b0ea6..2ed528e28d8 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -1172,7 +1172,7 @@ ProcessUtilitySlow(ParseState *pstate,
 							 * parse and validate reloptions for the toast
 							 * table
 							 */
-							toast_options = transformRelOptions((Datum) 0,
+							toast_options = transformRelOptions(DummyDatum,
 																cstmt->options,
 																"toast",
 																validnsps,
diff --git a/src/backend/tsearch/ts_typanalyze.c b/src/backend/tsearch/ts_typanalyze.c
index c5a71331ce8..98bfe79a43a 100644
--- a/src/backend/tsearch/ts_typanalyze.c
+++ b/src/backend/tsearch/ts_typanalyze.c
@@ -285,7 +285,7 @@ compute_tsvector_stats(VacAttrStats *stats,
 		}
 
 		/* If the vector was toasted, free the detoasted copy. */
-		if (TSVectorGetDatum(vector) != value)
+		if (TSVectorGetDatum(vector).value != value.value)
 			pfree(vector);
 	}
 
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index a8ddb610991..03036782ba9 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -62,7 +62,7 @@ tt_setup_firstcall(FuncCallContext *funcctx, FunctionCallInfo fcinfo,
 	st->cur = 0;
 	/* lextype takes one dummy argument */
 	st->list = (LexDescr *) DatumGetPointer(OidFunctionCall1(prs->lextypeOid,
-															 (Datum) 0));
+															 DummyDatum));
 	funcctx->user_fctx = st;
 
 	if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
@@ -99,7 +99,7 @@ tt_process_call(FuncCallContext *funcctx)
 		st->cur++;
 		return result;
 	}
-	return (Datum) 0;
+	return DummyDatum;
 }
 
 Datum
@@ -116,7 +116,8 @@ ts_token_type_byid(PG_FUNCTION_ARGS)
 
 	funcctx = SRF_PERCALL_SETUP();
 
-	if ((result = tt_process_call(funcctx)) != (Datum) 0)
+	result = tt_process_call(funcctx);
+	if (result.value != DummyDatum.value)
 		SRF_RETURN_NEXT(funcctx, result);
 	SRF_RETURN_DONE(funcctx);
 }
@@ -139,7 +140,8 @@ ts_token_type_byname(PG_FUNCTION_ARGS)
 
 	funcctx = SRF_PERCALL_SETUP();
 
-	if ((result = tt_process_call(funcctx)) != (Datum) 0)
+	result = tt_process_call(funcctx);
+	if (result.value != DummyDatum.value)
 		SRF_RETURN_NEXT(funcctx, result);
 	SRF_RETURN_DONE(funcctx);
 }
@@ -235,7 +237,7 @@ prs_process_call(FuncCallContext *funcctx)
 		st->cur++;
 		return result;
 	}
-	return (Datum) 0;
+	return DummyDatum;
 }
 
 Datum
@@ -255,7 +257,8 @@ ts_parse_byid(PG_FUNCTION_ARGS)
 
 	funcctx = SRF_PERCALL_SETUP();
 
-	if ((result = prs_process_call(funcctx)) != (Datum) 0)
+	result = prs_process_call(funcctx);
+	if (result.value != DummyDatum.value)
 		SRF_RETURN_NEXT(funcctx, result);
 	SRF_RETURN_DONE(funcctx);
 }
@@ -279,7 +282,8 @@ ts_parse_byname(PG_FUNCTION_ARGS)
 
 	funcctx = SRF_PERCALL_SETUP();
 
-	if ((result = prs_process_call(funcctx)) != (Datum) 0)
+	result = prs_process_call(funcctx);
+	if (result.value != DummyDatum.value)
 		SRF_RETURN_NEXT(funcctx, result);
 	SRF_RETURN_DONE(funcctx);
 }
diff --git a/src/backend/utils/activity/backend_status.c b/src/backend/utils/activity/backend_status.c
index a290cc4c975..22ec4bfc870 100644
--- a/src/backend/utils/activity/backend_status.c
+++ b/src/backend/utils/activity/backend_status.c
@@ -250,7 +250,7 @@ pgstat_beinit(void)
 	MyBEEntry = &BackendStatusArray[MyProcNumber];
 
 	/* Set up a process-exit hook to clean up */
-	on_shmem_exit(pgstat_beshutdown_hook, 0);
+	on_shmem_exit(pgstat_beshutdown_hook, DummyDatum);
 }
 
 
diff --git a/src/backend/utils/activity/pgstat.c b/src/backend/utils/activity/pgstat.c
index ffb5b8cce34..3b2380b51bf 100644
--- a/src/backend/utils/activity/pgstat.c
+++ b/src/backend/utils/activity/pgstat.c
@@ -657,7 +657,7 @@ pgstat_initialize(void)
 	}
 
 	/* Set up a process-exit hook to clean up */
-	before_shmem_exit(pgstat_shutdown_hook, 0);
+	before_shmem_exit(pgstat_shutdown_hook, DummyDatum);
 
 #ifdef USE_ASSERT_CHECKING
 	pgstat_is_initialized = true;
diff --git a/src/backend/utils/activity/pgstat_shmem.c b/src/backend/utils/activity/pgstat_shmem.c
index 53e7d534270..921e585216f 100644
--- a/src/backend/utils/activity/pgstat_shmem.c
+++ b/src/backend/utils/activity/pgstat_shmem.c
@@ -805,7 +805,7 @@ pgstat_release_all_entry_refs(bool discard_pending)
 	if (pgStatEntryRefHash == NULL)
 		return;
 
-	pgstat_release_matching_entry_refs(discard_pending, NULL, 0);
+	pgstat_release_matching_entry_refs(discard_pending, NULL, DummyDatum);
 	Assert(pgStatEntryRefHash->members == 0);
 	pgstat_entry_ref_hash_destroy(pgStatEntryRefHash);
 	pgStatEntryRefHash = NULL;
@@ -1051,7 +1051,7 @@ pgstat_drop_matching_entries(bool (*do_drop) (PgStatShared_HashEntry *, Datum),
 void
 pgstat_drop_all_entries(void)
 {
-	pgstat_drop_matching_entries(NULL, 0);
+	pgstat_drop_matching_entries(NULL, DummyDatum);
 }
 
 static void
diff --git a/src/backend/utils/activity/wait_event_funcs.c b/src/backend/utils/activity/wait_event_funcs.c
index ffbb57a8078..9c2489a81c8 100644
--- a/src/backend/utils/activity/wait_event_funcs.c
+++ b/src/backend/utils/activity/wait_event_funcs.c
@@ -114,5 +114,5 @@ pg_get_wait_events(PG_FUNCTION_ARGS)
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
 
-	return (Datum) 0;
+	PG_RETURN_DUMMY();
 }
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index 1213f9106d5..9dc410fe66c 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -628,7 +628,7 @@ aclitemin(PG_FUNCTION_ARGS)
 	while (isspace((unsigned char) *s))
 		++s;
 	if (*s)
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("extra garbage at the end of the ACL specification")));
 
@@ -5053,13 +5053,13 @@ initialize_acl(void)
 		 */
 		CacheRegisterSyscacheCallback(AUTHMEMROLEMEM,
 									  RoleMembershipCacheCallback,
-									  (Datum) 0);
+									  DummyDatum);
 		CacheRegisterSyscacheCallback(AUTHOID,
 									  RoleMembershipCacheCallback,
-									  (Datum) 0);
+									  DummyDatum);
 		CacheRegisterSyscacheCallback(DATABASEOID,
 									  RoleMembershipCacheCallback,
-									  (Datum) 0);
+									  DummyDatum);
 	}
 }
 
diff --git a/src/backend/utils/adt/array_selfuncs.c b/src/backend/utils/adt/array_selfuncs.c
index a69a84c2aee..42390d8308f 100644
--- a/src/backend/utils/adt/array_selfuncs.c
+++ b/src/backend/utils/adt/array_selfuncs.c
@@ -411,7 +411,7 @@ calc_arraycontsel(VariableStatData *vardata, Datum constval,
 	}
 
 	/* If constant was toasted, release the copy we made */
-	if (PointerGetDatum(array) != constval)
+	if (PointerGetDatum(array).value != constval.value)
 		pfree(array);
 
 	return selec;
diff --git a/src/backend/utils/adt/array_typanalyze.c b/src/backend/utils/adt/array_typanalyze.c
index 6f61629b977..7e4e3fbbf79 100644
--- a/src/backend/utils/adt/array_typanalyze.c
+++ b/src/backend/utils/adt/array_typanalyze.c
@@ -426,7 +426,7 @@ compute_array_stats(VacAttrStats *stats, AnalyzeAttrFetchFunc fetchfunc,
 			count_item->frequency = 1;
 
 		/* Free memory allocated while detoasting. */
-		if (PointerGetDatum(array) != value)
+		if (PointerGetDatum(array).value != value.value)
 			pfree(array);
 		pfree(elem_values);
 		pfree(elem_nulls);
diff --git a/src/backend/utils/adt/array_userfuncs.c b/src/backend/utils/adt/array_userfuncs.c
index 8eb342e3382..3cb437849d5 100644
--- a/src/backend/utils/adt/array_userfuncs.c
+++ b/src/backend/utils/adt/array_userfuncs.c
@@ -150,7 +150,7 @@ array_append(PG_FUNCTION_ARGS)
 	eah = fetch_array_arg_replace_nulls(fcinfo, 0);
 	isNull = PG_ARGISNULL(1);
 	if (isNull)
-		newelem = (Datum) 0;
+		newelem = DummyDatum;
 	else
 		newelem = PG_GETARG_DATUM(1);
 
@@ -232,7 +232,7 @@ array_prepend(PG_FUNCTION_ARGS)
 
 	isNull = PG_ARGISNULL(0);
 	if (isNull)
-		newelem = (Datum) 0;
+		newelem = DummyDatum;
 	else
 		newelem = PG_GETARG_DATUM(0);
 	eah = fetch_array_arg_replace_nulls(fcinfo, 1);
@@ -266,7 +266,7 @@ array_prepend(PG_FUNCTION_ARGS)
 							   -1, my_extra->typlen, my_extra->typbyval, my_extra->typalign);
 
 	/* Readjust result's LB to match the input's, as expected for prepend */
-	Assert(result == EOHPGetRWDatum(&eah->hdr));
+	Assert(result.value == EOHPGetRWDatum(&eah->hdr).value);
 	if (eah->ndims == 1)
 	{
 		/* This is ok whether we've deconstructed or not */
@@ -581,7 +581,7 @@ array_agg_transfn(PG_FUNCTION_ARGS)
 	else
 		state = (ArrayBuildState *) PG_GETARG_POINTER(0);
 
-	elem = PG_ARGISNULL(1) ? (Datum) 0 : PG_GETARG_DATUM(1);
+	elem = PG_ARGISNULL(1) ? DummyDatum : PG_GETARG_DATUM(1);
 
 	state = accumArrayResult(state,
 							 elem,
@@ -637,7 +637,7 @@ array_agg_combine(PG_FUNCTION_ARGS)
 											   state1->typbyval,
 											   state1->typlen);
 			else
-				state1->dvalues[i] = (Datum) 0;
+				state1->dvalues[i] = DummyDatum;
 		}
 
 		MemoryContextSwitchTo(old_context);
@@ -676,7 +676,7 @@ array_agg_combine(PG_FUNCTION_ARGS)
 							  state1->typbyval,
 							  state1->typlen);
 			else
-				state1->dvalues[i + state1->nelems] = (Datum) 0;
+				state1->dvalues[i + state1->nelems] = DummyDatum;
 		}
 
 		memcpy(&state1->dnulls[state1->nelems], state2->dnulls,
@@ -862,7 +862,7 @@ array_agg_deserialize(PG_FUNCTION_ARGS)
 
 			if (result->dnulls[i])
 			{
-				result->dvalues[i] = (Datum) 0;
+				result->dvalues[i] = DummyDatum;
 				continue;
 			}
 
@@ -1356,7 +1356,7 @@ array_position_common(FunctionCallInfo fcinfo)
 		/* fast return when the array doesn't have nulls */
 		if (!array_contains_nulls(array))
 			PG_RETURN_NULL();
-		searched_element = (Datum) 0;
+		searched_element = DummyDatum;
 		null_search = true;
 	}
 	else
@@ -1512,7 +1512,7 @@ array_positions(PG_FUNCTION_ARGS)
 		/* fast return when the array doesn't have nulls */
 		if (!array_contains_nulls(array))
 			PG_RETURN_DATUM(makeArrayResult(astate, CurrentMemoryContext));
-		searched_element = (Datum) 0;
+		searched_element = DummyDatum;
 		null_search = true;
 	}
 	else
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c
index c8f53c6fbe7..2651d1a0e0a 100644
--- a/src/backend/utils/adt/arrayfuncs.c
+++ b/src/backend/utils/adt/arrayfuncs.c
@@ -253,13 +253,13 @@ array_in(PG_FUNCTION_ARGS)
 	 */
 	p = string;
 	if (!ReadArrayDimensions(&p, &ndim, dim, lBound, string, escontext))
-		return (Datum) 0;
+		return DummyDatum;
 
 	if (ndim == 0)
 	{
 		/* No array dimensions, so next character should be a left brace */
 		if (*p != '{')
-			ereturn(escontext, (Datum) 0,
+			ereturn(escontext, DummyDatum,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("malformed array literal: \"%s\"", string),
 					 errdetail("Array value must start with \"{\" or dimension information.")));
@@ -268,7 +268,7 @@ array_in(PG_FUNCTION_ARGS)
 	{
 		/* If array dimensions are given, expect '=' operator */
 		if (strncmp(p, ASSGN, strlen(ASSGN)) != 0)
-			ereturn(escontext, (Datum) 0,
+			ereturn(escontext, DummyDatum,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("malformed array literal: \"%s\"", string),
 					 errdetail("Missing \"%s\" after array dimensions.",
@@ -279,7 +279,7 @@ array_in(PG_FUNCTION_ARGS)
 			p++;
 
 		if (*p != '{')
-			ereturn(escontext, (Datum) 0,
+			ereturn(escontext, DummyDatum,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("malformed array literal: \"%s\"", string),
 					 errdetail("Array contents must start with \"{\".")));
@@ -296,13 +296,13 @@ array_in(PG_FUNCTION_ARGS)
 					  &values, &nulls,
 					  string,
 					  escontext))
-		return (Datum) 0;
+		return DummyDatum;
 
 	/* only whitespace is allowed after the closing brace */
 	while (*p)
 	{
 		if (!scanner_isspace(*p++))
-			ereturn(escontext, (Datum) 0,
+			ereturn(escontext, DummyDatum,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("malformed array literal: \"%s\"", string),
 					 errdetail("Junk after closing right brace.")));
@@ -330,7 +330,7 @@ array_in(PG_FUNCTION_ARGS)
 			nbytes = att_align_nominal(nbytes, typalign);
 			/* check for overflow of total request */
 			if (!AllocSizeIsValid(nbytes))
-				ereturn(escontext, (Datum) 0,
+				ereturn(escontext, DummyDatum,
 						(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
 						 errmsg("array size exceeds the maximum allowed (%d)",
 								(int) MaxAllocSize)));
@@ -1880,14 +1880,14 @@ array_get_element(Datum arraydatum,
 	if (ndim != nSubscripts || ndim <= 0 || ndim > MAXDIM)
 	{
 		*isNull = true;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 	for (i = 0; i < ndim; i++)
 	{
 		if (indx[i] < lb[i] || indx[i] >= (dim[i] + lb[i]))
 		{
 			*isNull = true;
-			return (Datum) 0;
+			return DummyDatum;
 		}
 	}
 
@@ -1902,7 +1902,7 @@ array_get_element(Datum arraydatum,
 	if (array_get_isnull(arraynullsptr, offset))
 	{
 		*isNull = true;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 
 	/*
@@ -1952,14 +1952,14 @@ array_get_element_expanded(Datum arraydatum,
 	if (ndim != nSubscripts || ndim <= 0 || ndim > MAXDIM)
 	{
 		*isNull = true;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 	for (i = 0; i < ndim; i++)
 	{
 		if (indx[i] < lb[i] || indx[i] >= (dim[i] + lb[i]))
 		{
 			*isNull = true;
-			return (Datum) 0;
+			return DummyDatum;
 		}
 	}
 
@@ -1983,7 +1983,7 @@ array_get_element_expanded(Datum arraydatum,
 	if (dnulls && dnulls[offset])
 	{
 		*isNull = true;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 
 	/*
@@ -2711,7 +2711,7 @@ array_set_element_expanded(Datum arraydatum,
 	{
 		memmove(dvalues + addedbefore, dvalues, eah->nelems * sizeof(Datum));
 		for (i = 0; i < addedbefore; i++)
-			dvalues[i] = (Datum) 0;
+			dvalues[i] = DummyDatum;
 		if (dnulls)
 		{
 			memmove(dnulls + addedbefore, dnulls, eah->nelems * sizeof(bool));
@@ -2725,7 +2725,7 @@ array_set_element_expanded(Datum arraydatum,
 	if (addedafter > 0)
 	{
 		for (i = 0; i < addedafter; i++)
-			dvalues[eah->nelems + i] = (Datum) 0;
+			dvalues[eah->nelems + i] = DummyDatum;
 		if (dnulls)
 		{
 			for (i = 0; i < addedafter; i++)
@@ -3660,7 +3660,7 @@ deconstruct_array(ArrayType *array,
 		/* Get source element, checking for NULL */
 		if (bitmap && (*bitmap & bitmask) == 0)
 		{
-			elems[i] = (Datum) 0;
+			elems[i] = DummyDatum;
 			if (nulls)
 				nulls[i] = true;
 			else
@@ -4687,7 +4687,7 @@ array_iterate(ArrayIterator iterator, Datum *value, bool *isnull)
 		if (array_get_isnull(iterator->nullbitmap, iterator->current_item++))
 		{
 			*isnull = true;
-			*value = (Datum) 0;
+			*value = DummyDatum;
 		}
 		else
 		{
@@ -4720,7 +4720,7 @@ array_iterate(ArrayIterator iterator, Datum *value, bool *isnull)
 								 iterator->current_item++))
 			{
 				nulls[i] = true;
-				values[i] = (Datum) 0;
+				values[i] = DummyDatum;
 			}
 			else
 			{
@@ -6013,7 +6013,7 @@ array_fill_with_lower_bounds(PG_FUNCTION_ARGS)
 	}
 	else
 	{
-		value = 0;
+		value = DummyDatum;
 		isnull = true;
 	}
 
@@ -6052,7 +6052,7 @@ array_fill(PG_FUNCTION_ARGS)
 	}
 	else
 	{
-		value = 0;
+		value = DummyDatum;
 		isnull = true;
 	}
 
@@ -6648,7 +6648,7 @@ array_remove(PG_FUNCTION_ARGS)
 
 	array = array_replace_internal(array,
 								   search, search_isnull,
-								   (Datum) 0, true,
+								   DummyDatum, true,
 								   true, PG_GET_COLLATION(),
 								   fcinfo);
 	PG_RETURN_ARRAYTYPE_P(array);
diff --git a/src/backend/utils/adt/arraysubs.c b/src/backend/utils/adt/arraysubs.c
index 2940fb8e8d7..7d3880205bf 100644
--- a/src/backend/utils/adt/arraysubs.c
+++ b/src/backend/utils/adt/arraysubs.c
@@ -407,7 +407,7 @@ array_subscript_fetch_old(ExprState *state,
 	if (*op->resnull)
 	{
 		/* whole array is null, so any element is too */
-		sbsrefstate->prevvalue = (Datum) 0;
+		sbsrefstate->prevvalue = DummyDatum;
 		sbsrefstate->prevnull = true;
 	}
 	else
@@ -447,7 +447,7 @@ array_subscript_fetch_old_slice(ExprState *state,
 	if (*op->resnull)
 	{
 		/* whole array is null, so any slice is too */
-		sbsrefstate->prevvalue = (Datum) 0;
+		sbsrefstate->prevvalue = DummyDatum;
 		sbsrefstate->prevnull = true;
 	}
 	else
diff --git a/src/backend/utils/adt/bool.c b/src/backend/utils/adt/bool.c
index 474653797b5..5910ccfa3e5 100644
--- a/src/backend/utils/adt/bool.c
+++ b/src/backend/utils/adt/bool.c
@@ -145,7 +145,7 @@ boolin(PG_FUNCTION_ARGS)
 	if (parse_bool_with_len(str, len, &result))
 		PG_RETURN_BOOL(result);
 
-	ereturn(fcinfo->context, (Datum) 0,
+	ereturn(fcinfo->context, DummyDatum,
 			(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 			 errmsg("invalid input syntax for type %s: \"%s\"",
 					"boolean", in_str)));
diff --git a/src/backend/utils/adt/bytea.c b/src/backend/utils/adt/bytea.c
index 6e7b914c563..631f39a8183 100644
--- a/src/backend/utils/adt/bytea.c
+++ b/src/backend/utils/adt/bytea.c
@@ -239,7 +239,7 @@ byteain(PG_FUNCTION_ARGS)
 			/*
 			 * one backslash, not followed by another or ### valid octal
 			 */
-			ereturn(escontext, (Datum) 0,
+			ereturn(escontext, DummyDatum,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s", "bytea")));
 		}
diff --git a/src/backend/utils/adt/cash.c b/src/backend/utils/adt/cash.c
index 611d23f3cb0..6175ab77be9 100644
--- a/src/backend/utils/adt/cash.c
+++ b/src/backend/utils/adt/cash.c
@@ -287,7 +287,7 @@ cash_in(PG_FUNCTION_ARGS)
 
 			if (pg_mul_s64_overflow(value, 10, &value) ||
 				pg_sub_s64_overflow(value, digit, &value))
-				ereturn(escontext, (Datum) 0,
+				ereturn(escontext, DummyDatum,
 						(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 						 errmsg("value \"%s\" is out of range for type %s",
 								str, "money")));
@@ -312,7 +312,7 @@ cash_in(PG_FUNCTION_ARGS)
 	{
 		/* remember we build the value in the negative */
 		if (pg_sub_s64_overflow(value, 1, &value))
-			ereturn(escontext, (Datum) 0,
+			ereturn(escontext, DummyDatum,
 					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 					 errmsg("value \"%s\" is out of range for type %s",
 							str, "money")));
@@ -322,7 +322,7 @@ cash_in(PG_FUNCTION_ARGS)
 	for (; dec < fpoint; dec++)
 	{
 		if (pg_mul_s64_overflow(value, 10, &value))
-			ereturn(escontext, (Datum) 0,
+			ereturn(escontext, DummyDatum,
 					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 					 errmsg("value \"%s\" is out of range for type %s",
 							str, "money")));
@@ -349,7 +349,7 @@ cash_in(PG_FUNCTION_ARGS)
 		else if (strncmp(s, csymbol, strlen(csymbol)) == 0)
 			s += strlen(csymbol);
 		else
-			ereturn(escontext, (Datum) 0,
+			ereturn(escontext, DummyDatum,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
 							"money", str)));
@@ -362,7 +362,7 @@ cash_in(PG_FUNCTION_ARGS)
 	if (sgn > 0)
 	{
 		if (value == PG_INT64_MIN)
-			ereturn(escontext, (Datum) 0,
+			ereturn(escontext, DummyDatum,
 					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 					 errmsg("value \"%s\" is out of range for type %s",
 							str, "money")));
diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c
index 344f58b92f7..e91932cc168 100644
--- a/src/backend/utils/adt/date.c
+++ b/src/backend/utils/adt/date.c
@@ -163,7 +163,7 @@ date_in(PG_FUNCTION_ARGS)
 
 	/* Prevent overflow in Julian-day routines */
 	if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
 				 errmsg("date out of range: \"%s\"", str)));
 
@@ -171,7 +171,7 @@ date_in(PG_FUNCTION_ARGS)
 
 	/* Now check for just-out-of-range dates */
 	if (!IS_VALID_DATE(date))
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
 				 errmsg("date out of range: \"%s\"", str)));
 
@@ -472,7 +472,7 @@ date_decrement(Relation rel, Datum existing, bool *underflow)
 	{
 		/* return value is undefined */
 		*underflow = true;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 
 	*underflow = false;
@@ -488,7 +488,7 @@ date_increment(Relation rel, Datum existing, bool *overflow)
 	{
 		/* return value is undefined */
 		*overflow = true;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 
 	*overflow = false;
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 680fee2a844..f92f7a49d0d 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -5388,5 +5388,5 @@ pg_timezone_names(PG_FUNCTION_ARGS)
 	}
 
 	pg_tzenumerate_end(tzenum);
-	return (Datum) 0;
+	return DummyDatum;
 }
diff --git a/src/backend/utils/adt/datum.c b/src/backend/utils/adt/datum.c
index 614644a4e2a..37685a8113a 100644
--- a/src/backend/utils/adt/datum.c
+++ b/src/backend/utils/adt/datum.c
@@ -232,7 +232,7 @@ datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
 		 * inside the "Datum".  We assume instead that any given datatype is
 		 * consistent about how it fills extraneous bits in the Datum.
 		 */
-		res = (value1 == value2);
+		res = (value1.value == value2.value);
 	}
 	else
 	{
@@ -271,7 +271,7 @@ datum_image_eq(Datum value1, Datum value2, bool typByVal, int typLen)
 
 	if (typByVal)
 	{
-		result = (value1 == value2);
+		result = (value1.value == value2.value);
 	}
 	else if (typLen > 0)
 	{
@@ -531,7 +531,7 @@ datumRestore(char **start_address, bool *isnull)
 	if (header == -2)
 	{
 		*isnull = true;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 
 	/* OK, datum is not null. */
diff --git a/src/backend/utils/adt/enum.c b/src/backend/utils/adt/enum.c
index fcc6981632b..f0e563033d2 100644
--- a/src/backend/utils/adt/enum.c
+++ b/src/backend/utils/adt/enum.c
@@ -116,7 +116,7 @@ enum_in(PG_FUNCTION_ARGS)
 
 	/* must check length to prevent Assert failure within SearchSysCache */
 	if (strlen(name) >= NAMEDATALEN)
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input value for enum %s: \"%s\"",
 						format_type_be(enumtypoid),
@@ -126,7 +126,7 @@ enum_in(PG_FUNCTION_ARGS)
 						  ObjectIdGetDatum(enumtypoid),
 						  CStringGetDatum(name));
 	if (!HeapTupleIsValid(tup))
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input value for enum %s: \"%s\"",
 						format_type_be(enumtypoid),
diff --git a/src/backend/utils/adt/expandedrecord.c b/src/backend/utils/adt/expandedrecord.c
index 13752db44e8..69c8b75cede 100644
--- a/src/backend/utils/adt/expandedrecord.c
+++ b/src/backend/utils/adt/expandedrecord.c
@@ -1069,7 +1069,7 @@ expanded_record_fetch_field(ExpandedRecordHeader *erh, int fnumber,
 		if (ExpandedRecordIsEmpty(erh))
 		{
 			*isnull = true;
-			return (Datum) 0;
+			return DummyDatum;
 		}
 		/* Make sure we have deconstructed form */
 		deconstruct_expanded_record(erh);
@@ -1077,7 +1077,7 @@ expanded_record_fetch_field(ExpandedRecordHeader *erh, int fnumber,
 		if (unlikely(fnumber > erh->nfields))
 		{
 			*isnull = true;
-			return (Datum) 0;
+			return DummyDatum;
 		}
 		*isnull = erh->dnulls[fnumber - 1];
 		return erh->dvalues[fnumber - 1];
@@ -1088,7 +1088,7 @@ expanded_record_fetch_field(ExpandedRecordHeader *erh, int fnumber,
 		if (erh->fvalue == NULL)
 		{
 			*isnull = true;
-			return (Datum) 0;
+			return DummyDatum;
 		}
 		/* heap_getsysattr doesn't actually use tupdesc, so just pass null */
 		return heap_getsysattr(erh->fvalue, fnumber, NULL, isnull);
@@ -1584,7 +1584,7 @@ check_domain_for_new_tuple(ExpandedRecordHeader *erh, HeapTuple tuple)
 		/* We run domain_check in a short-lived context to limit cruft */
 		oldcxt = MemoryContextSwitchTo(get_short_term_cxt(erh));
 
-		domain_check((Datum) 0, true,
+		domain_check(DummyDatum, true,
 					 erh->er_decltypeid,
 					 &erh->er_domaininfo,
 					 erh->hdr.eoh_context);
diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c
index 1d05481181d..9e6b9ff303b 100644
--- a/src/backend/utils/adt/formatting.c
+++ b/src/backend/utils/adt/formatting.c
@@ -4212,7 +4212,7 @@ parse_datetime(text *date_txt, text *fmt, Oid collid, bool strict,
 
 	if (!do_to_timestamp(date_txt, fmt, collid, strict,
 						 &tm, &fsec, &ftz, &fprec, &flags, escontext))
-		return (Datum) 0;
+		return DummyDatum;
 
 	*typmod = fprec ? fprec : -1;	/* fractional part precision */
 
@@ -4237,13 +4237,13 @@ parse_datetime(text *date_txt, text *fmt, Oid collid, bool strict,
 					 */
 					Assert(!strict);
 
-					ereturn(escontext, (Datum) 0,
+					ereturn(escontext, DummyDatum,
 							(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
 							 errmsg("missing time zone in input string for type timestamptz")));
 				}
 
 				if (tm2timestamp(&tm, fsec, tz, &result) != 0)
-					ereturn(escontext, (Datum) 0,
+					ereturn(escontext, DummyDatum,
 							(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
 							 errmsg("timestamptz out of range")));
 
@@ -4257,7 +4257,7 @@ parse_datetime(text *date_txt, text *fmt, Oid collid, bool strict,
 				Timestamp	result;
 
 				if (tm2timestamp(&tm, fsec, NULL, &result) != 0)
-					ereturn(escontext, (Datum) 0,
+					ereturn(escontext, DummyDatum,
 							(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
 							 errmsg("timestamp out of range")));
 
@@ -4271,7 +4271,7 @@ parse_datetime(text *date_txt, text *fmt, Oid collid, bool strict,
 		{
 			if (flags & DCH_ZONED)
 			{
-				ereturn(escontext, (Datum) 0,
+				ereturn(escontext, DummyDatum,
 						(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
 						 errmsg("datetime format is zoned but not timed")));
 			}
@@ -4281,7 +4281,7 @@ parse_datetime(text *date_txt, text *fmt, Oid collid, bool strict,
 
 				/* Prevent overflow in Julian-day routines */
 				if (!IS_VALID_JULIAN(tm.tm_year, tm.tm_mon, tm.tm_mday))
-					ereturn(escontext, (Datum) 0,
+					ereturn(escontext, DummyDatum,
 							(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
 							 errmsg("date out of range: \"%s\"",
 									text_to_cstring(date_txt))));
@@ -4291,7 +4291,7 @@ parse_datetime(text *date_txt, text *fmt, Oid collid, bool strict,
 
 				/* Now check for just-out-of-range dates */
 				if (!IS_VALID_DATE(result))
-					ereturn(escontext, (Datum) 0,
+					ereturn(escontext, DummyDatum,
 							(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
 							 errmsg("date out of range: \"%s\"",
 									text_to_cstring(date_txt))));
@@ -4320,13 +4320,13 @@ parse_datetime(text *date_txt, text *fmt, Oid collid, bool strict,
 				 */
 				Assert(!strict);
 
-				ereturn(escontext, (Datum) 0,
+				ereturn(escontext, DummyDatum,
 						(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
 						 errmsg("missing time zone in input string for type timetz")));
 			}
 
 			if (tm2timetz(&tm, fsec, *tz, result) != 0)
-				ereturn(escontext, (Datum) 0,
+				ereturn(escontext, DummyDatum,
 						(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
 						 errmsg("timetz out of range")));
 
@@ -4340,7 +4340,7 @@ parse_datetime(text *date_txt, text *fmt, Oid collid, bool strict,
 			TimeADT		result;
 
 			if (tm2time(&tm, fsec, &result) != 0)
-				ereturn(escontext, (Datum) 0,
+				ereturn(escontext, DummyDatum,
 						(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
 						 errmsg("time out of range")));
 
@@ -4352,7 +4352,7 @@ parse_datetime(text *date_txt, text *fmt, Oid collid, bool strict,
 	}
 	else
 	{
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_INVALID_DATETIME_FORMAT),
 				 errmsg("datetime format is not dated and not timed")));
 	}
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 80bb807fbe9..6d24bf69ff6 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -522,7 +522,7 @@ pg_ls_dir(PG_FUNCTION_ARGS)
 	{
 		/* Return empty tuplestore if appropriate */
 		if (missing_ok && errno == ENOENT)
-			return (Datum) 0;
+			return DummyDatum;
 		/* Otherwise, we can let ReadDir() throw the error */
 	}
 
@@ -544,7 +544,7 @@ pg_ls_dir(PG_FUNCTION_ARGS)
 	}
 
 	FreeDir(dirdesc);
-	return (Datum) 0;
+	return DummyDatum;
 }
 
 /*
@@ -585,7 +585,7 @@ pg_ls_dir_files(FunctionCallInfo fcinfo, const char *dir, bool missing_ok)
 	{
 		/* Return empty tuplestore if appropriate */
 		if (missing_ok && errno == ENOENT)
-			return (Datum) 0;
+			return DummyDatum;
 		/* Otherwise, we can let ReadDir() throw the error */
 	}
 
@@ -625,7 +625,7 @@ pg_ls_dir_files(FunctionCallInfo fcinfo, const char *dir, bool missing_ok)
 	}
 
 	FreeDir(dirdesc);
-	return (Datum) 0;
+	return DummyDatum;
 }
 
 /* Function to return the list of files in the log directory */
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 377a1b3f3ad..38d8caf8478 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -993,7 +993,7 @@ line_in(PG_FUNCTION_ARGS)
 		if (!line_decode(s + 1, str, line, escontext))
 			PG_RETURN_NULL();
 		if (FPzero(line->A) && FPzero(line->B))
-			ereturn(escontext, (Datum) 0,
+			ereturn(escontext, DummyDatum,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid line specification: A and B cannot both be zero")));
 	}
@@ -1003,7 +1003,7 @@ line_in(PG_FUNCTION_ARGS)
 						 escontext))
 			PG_RETURN_NULL();
 		if (point_eq_point(&lseg.p[0], &lseg.p[1]))
-			ereturn(escontext, (Datum) 0,
+			ereturn(escontext, DummyDatum,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid line specification: must be two distinct points")));
 
@@ -1412,7 +1412,7 @@ path_in(PG_FUNCTION_ARGS)
 	int			depth = 0;
 
 	if ((npts = pair_count(str, ',')) <= 0)
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"path", str)));
@@ -1433,7 +1433,7 @@ path_in(PG_FUNCTION_ARGS)
 
 	/* Check for integer overflow */
 	if (base_size / npts != sizeof(path->p[0]) || size <= base_size)
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
 				 errmsg("too many points requested")));
 
@@ -1449,7 +1449,7 @@ path_in(PG_FUNCTION_ARGS)
 	if (depth >= 1)
 	{
 		if (*s++ != RDELIM)
-			ereturn(escontext, (Datum) 0,
+			ereturn(escontext, DummyDatum,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
 							"path", str)));
@@ -1457,7 +1457,7 @@ path_in(PG_FUNCTION_ARGS)
 			s++;
 	}
 	if (*s != '\0')
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"path", str)));
@@ -3423,7 +3423,7 @@ poly_in(PG_FUNCTION_ARGS)
 	bool		isopen;
 
 	if ((npts = pair_count(str, ',')) <= 0)
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"polygon", str)));
@@ -3433,7 +3433,7 @@ poly_in(PG_FUNCTION_ARGS)
 
 	/* Check for integer overflow */
 	if (base_size / npts != sizeof(poly->p[0]) || size <= base_size)
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
 				 errmsg("too many points requested")));
 
@@ -4645,7 +4645,7 @@ circle_in(PG_FUNCTION_ARGS)
 
 	/* We have to accept NaN. */
 	if (circle->radius < 0.0)
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"circle", str)));
@@ -4660,14 +4660,14 @@ circle_in(PG_FUNCTION_ARGS)
 				s++;
 		}
 		else
-			ereturn(escontext, (Datum) 0,
+			ereturn(escontext, DummyDatum,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
 							"circle", str)));
 	}
 
 	if (*s != '\0')
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"circle", str)));
diff --git a/src/backend/utils/adt/int.c b/src/backend/utils/adt/int.c
index b5781989a64..313402cb14b 100644
--- a/src/backend/utils/adt/int.c
+++ b/src/backend/utils/adt/int.c
@@ -169,19 +169,19 @@ int2vectorin(PG_FUNCTION_ARGS)
 		l = strtol(intString, &endp, 10);
 
 		if (intString == endp)
-			ereturn(escontext, (Datum) 0,
+			ereturn(escontext, DummyDatum,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
 							"smallint", intString)));
 
 		if (errno == ERANGE || l < SHRT_MIN || l > SHRT_MAX)
-			ereturn(escontext, (Datum) 0,
+			ereturn(escontext, DummyDatum,
 					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 					 errmsg("value \"%s\" is out of range for type %s", intString,
 							"smallint")));
 
 		if (*endp && *endp != ' ')
-			ereturn(escontext, (Datum) 0,
+			ereturn(escontext, DummyDatum,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("invalid input syntax for type %s: \"%s\"",
 							"smallint", intString)));
diff --git a/src/backend/utils/adt/json.c b/src/backend/utils/adt/json.c
index e9d370cb3da..a241d459249 100644
--- a/src/backend/utils/adt/json.c
+++ b/src/backend/utils/adt/json.c
@@ -827,7 +827,7 @@ json_agg_transfn_worker(FunctionCallInfo fcinfo, bool absent_on_null)
 	/* fast path for NULLs */
 	if (PG_ARGISNULL(1))
 	{
-		datum_to_json_internal((Datum) 0, true, state->str, JSONTYPE_NULL,
+		datum_to_json_internal(DummyDatum, true, state->str, JSONTYPE_NULL,
 							   InvalidOid, false);
 		PG_RETURN_POINTER(state);
 	}
@@ -1132,7 +1132,7 @@ json_object_agg_transfn_worker(FunctionCallInfo fcinfo,
 	appendStringInfoString(state->str, " : ");
 
 	if (PG_ARGISNULL(2))
-		arg = (Datum) 0;
+		arg = DummyDatum;
 	else
 		arg = PG_GETARG_DATUM(2);
 
diff --git a/src/backend/utils/adt/jsonb.c b/src/backend/utils/adt/jsonb.c
index da94d424d61..fde816d2d7f 100644
--- a/src/backend/utils/adt/jsonb.c
+++ b/src/backend/utils/adt/jsonb.c
@@ -267,7 +267,7 @@ jsonb_from_cstring(char *json, int len, bool unique_keys, Node *escontext)
 	sem.object_field_start = jsonb_in_object_field_start;
 
 	if (!pg_parse_json_or_errsave(&lex, &sem, escontext))
-		return (Datum) 0;
+		return DummyDatum;
 
 	/* after parsing, the item member has the composed jsonb structure */
 	PG_RETURN_POINTER(JsonbValueToJsonb(state.res));
@@ -1551,7 +1551,7 @@ jsonb_agg_transfn_worker(FunctionCallInfo fcinfo, bool absent_on_null)
 
 	/* turn the argument into jsonb in the normal function context */
 
-	val = PG_ARGISNULL(1) ? (Datum) 0 : PG_GETARG_DATUM(1);
+	val = PG_ARGISNULL(1) ? DummyDatum : PG_GETARG_DATUM(1);
 
 	memset(&elem, 0, sizeof(JsonbInState));
 
@@ -1761,7 +1761,7 @@ jsonb_object_agg_transfn_worker(FunctionCallInfo fcinfo,
 
 	jbkey = JsonbValueToJsonb(elem.res);
 
-	val = PG_ARGISNULL(2) ? (Datum) 0 : PG_GETARG_DATUM(2);
+	val = PG_ARGISNULL(2) ? DummyDatum : PG_GETARG_DATUM(2);
 
 	memset(&elem, 0, sizeof(JsonbInState));
 
diff --git a/src/backend/utils/adt/jsonb_gin.c b/src/backend/utils/adt/jsonb_gin.c
index 9b56248cf0b..316cdcce4b0 100644
--- a/src/backend/utils/adt/jsonb_gin.c
+++ b/src/backend/utils/adt/jsonb_gin.c
@@ -1401,7 +1401,7 @@ make_scalar_key(const JsonbValue *scalarVal, bool is_key)
 			break;
 		default:
 			elog(ERROR, "unrecognized jsonb scalar type: %d", scalarVal->type);
-			item = 0;			/* keep compiler quiet */
+			item = DummyDatum;			/* keep compiler quiet */
 			break;
 	}
 
diff --git a/src/backend/utils/adt/jsonbsubs.c b/src/backend/utils/adt/jsonbsubs.c
index de64d498512..e936a447888 100644
--- a/src/backend/utils/adt/jsonbsubs.c
+++ b/src/backend/utils/adt/jsonbsubs.c
@@ -329,7 +329,7 @@ jsonb_subscript_fetch_old(ExprState *state,
 	if (*op->resnull)
 	{
 		/* whole jsonb is null, so any element is too */
-		sbsrefstate->prevvalue = (Datum) 0;
+		sbsrefstate->prevvalue = DummyDatum;
 		sbsrefstate->prevnull = true;
 	}
 	else
diff --git a/src/backend/utils/adt/jsonfuncs.c b/src/backend/utils/adt/jsonfuncs.c
index 370456408bf..a1453956b54 100644
--- a/src/backend/utils/adt/jsonfuncs.c
+++ b/src/backend/utils/adt/jsonfuncs.c
@@ -2027,7 +2027,7 @@ each_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, bool as_text)
 				{
 					/* a json null is an sql null in text mode */
 					nulls[1] = true;
-					values[1] = (Datum) NULL;
+					values[1] = DummyDatum;
 				}
 				else
 					values[1] = PointerGetDatum(JsonbValueAsText(&v));
@@ -2139,7 +2139,7 @@ each_object_field_end(void *state, char *fname, bool isnull)
 	if (isnull && _state->normalize_results)
 	{
 		nulls[1] = true;
-		values[1] = (Datum) 0;
+		values[1] = DummyDatum;
 	}
 	else if (_state->next_scalar)
 	{
@@ -2266,7 +2266,7 @@ elements_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname,
 				{
 					/* a json null is an sql null in text mode */
 					nulls[0] = true;
-					values[0] = (Datum) NULL;
+					values[0] = DummyDatum;
 				}
 				else
 					values[0] = PointerGetDatum(JsonbValueAsText(&v));
@@ -2389,7 +2389,7 @@ elements_array_element_end(void *state, bool isnull)
 	if (isnull && _state->normalize_results)
 	{
 		nulls[0] = true;
-		values[0] = (Datum) NULL;
+		values[0] = DummyDatum;
 	}
 	else if (_state->next_scalar)
 	{
@@ -2942,7 +2942,7 @@ populate_array(ArrayIOData *aio,
 								 : strlen(jsv->val.json.str)))
 		{
 			*isnull = true;
-			return (Datum) 0;
+			return DummyDatum;
 		}
 	}
 	else
@@ -2951,7 +2951,7 @@ populate_array(ArrayIOData *aio,
 		if (!populate_array_dim_jsonb(&ctx, jsv->val.jsonb, 1))
 		{
 			*isnull = true;
-			return (Datum) 0;
+			return DummyDatum;
 		}
 		ctx.dims[0] = ctx.sizes[0];
 	}
@@ -3070,7 +3070,7 @@ populate_composite(CompositeIOData *io,
 	update_cached_tupdesc(io, mcxt);
 
 	if (*isnull)
-		result = (Datum) 0;
+		result = DummyDatum;
 	else
 	{
 		HeapTupleHeader tuple;
@@ -3080,7 +3080,7 @@ populate_composite(CompositeIOData *io,
 		if (!JsValueToJsObject(jsv, &jso, escontext))
 		{
 			*isnull = true;
-			return (Datum) 0;
+			return DummyDatum;
 		}
 
 		/* populate resulting record tuple */
@@ -3090,7 +3090,7 @@ populate_composite(CompositeIOData *io,
 		if (SOFT_ERROR_OCCURRED(escontext))
 		{
 			*isnull = true;
-			return (Datum) 0;
+			return DummyDatum;
 		}
 		result = HeapTupleHeaderGetDatum(tuple);
 
@@ -3108,7 +3108,7 @@ populate_composite(CompositeIOData *io,
 							   escontext))
 		{
 			*isnull = true;
-			return (Datum) 0;
+			return DummyDatum;
 		}
 	}
 
@@ -3202,7 +3202,7 @@ populate_scalar(ScalarIOData *io, Oid typid, int32 typmod, JsValue *jsv,
 	if (!InputFunctionCallSafe(&io->typiofunc, str, io->typioparam, typmod,
 							   escontext, &res))
 	{
-		res = (Datum) 0;
+		res = DummyDatum;
 		*isnull = true;
 	}
 
@@ -3226,7 +3226,7 @@ populate_domain(DomainIOData *io,
 	Datum		res;
 
 	if (*isnull)
-		res = (Datum) 0;
+		res = DummyDatum;
 	else
 	{
 		res = populate_record_field(io->base_io,
@@ -3240,7 +3240,7 @@ populate_domain(DomainIOData *io,
 						   escontext))
 	{
 		*isnull = true;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 
 	return res;
@@ -3440,7 +3440,7 @@ populate_record_field(ColumnIOData *col,
 	if (*isnull &&
 		typcat != TYPECAT_DOMAIN &&
 		typcat != TYPECAT_COMPOSITE_DOMAIN)
-		return (Datum) 0;
+		return DummyDatum;
 
 	switch (typcat)
 	{
@@ -3468,7 +3468,7 @@ populate_record_field(ColumnIOData *col,
 
 		default:
 			elog(ERROR, "unrecognized type category '%c'", typcat);
-			return (Datum) 0;
+			return DummyDatum;
 	}
 }
 
@@ -3575,7 +3575,7 @@ populate_record(TupleDesc tupdesc,
 	{
 		for (i = 0; i < ncolumns; ++i)
 		{
-			values[i] = (Datum) 0;
+			values[i] = DummyDatum;
 			nulls[i] = true;
 		}
 	}
@@ -3612,7 +3612,7 @@ populate_record(TupleDesc tupdesc,
 										  att->atttypmod,
 										  colname,
 										  mcxt,
-										  nulls[i] ? (Datum) 0 : values[i],
+										  nulls[i] ? DummyDatum : values[i],
 										  &field,
 										  &nulls[i],
 										  escontext,
@@ -4946,7 +4946,7 @@ jsonb_set_lax(PG_FUNCTION_ARGS)
 				 errmsg("JSON value must not be null"),
 				 errdetail("Exception was raised because null_value_treatment is \"raise_exception\"."),
 				 errhint("To avoid, either change the null_value_treatment argument or ensure that an SQL NULL is not passed.")));
-		return (Datum) 0;		/* silence stupider compilers */
+		return DummyDatum;		/* silence stupider compilers */
 	}
 	else if (strcmp(handle_val, "use_json_null") == 0)
 	{
@@ -4973,7 +4973,7 @@ jsonb_set_lax(PG_FUNCTION_ARGS)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("null_value_treatment must be \"delete_key\", \"return_target\", \"use_json_null\", or \"raise_exception\"")));
-		return (Datum) 0;		/* silence stupider compilers */
+		return DummyDatum;		/* silence stupider compilers */
 	}
 }
 
diff --git a/src/backend/utils/adt/jsonpath.c b/src/backend/utils/adt/jsonpath.c
index 762f7e8a09d..7c58223eaf7 100644
--- a/src/backend/utils/adt/jsonpath.c
+++ b/src/backend/utils/adt/jsonpath.c
@@ -177,10 +177,10 @@ jsonPathFromCstring(char *in, int len, struct Node *escontext)
 	StringInfoData buf;
 
 	if (SOFT_ERROR_OCCURRED(escontext))
-		return (Datum) 0;
+		return DummyDatum;
 
 	if (!jsonpath)
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"", "jsonpath",
 						in)));
@@ -192,7 +192,7 @@ jsonPathFromCstring(char *in, int len, struct Node *escontext)
 
 	if (!flattenJsonPathParseItem(&buf, NULL, escontext,
 								  jsonpath->expr, 0, false))
-		return (Datum) 0;
+		return DummyDatum;
 
 	res = (JsonPath *) buf.data;
 	SET_VARSIZE(res, buf.len);
diff --git a/src/backend/utils/adt/jsonpath_exec.c b/src/backend/utils/adt/jsonpath_exec.c
index 5a562535223..577fbbca12c 100644
--- a/src/backend/utils/adt/jsonpath_exec.c
+++ b/src/backend/utils/adt/jsonpath_exec.c
@@ -3925,7 +3925,7 @@ JsonPathQuery(Datum jb, JsonPath *jp, JsonWrapper wrapper, bool *empty,
 	{
 		*error = true;
 		*empty = false;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 
 	/*
@@ -3971,7 +3971,7 @@ JsonPathQuery(Datum jb, JsonPath *jp, JsonWrapper wrapper, bool *empty,
 		if (error)
 		{
 			*error = true;
-			return (Datum) 0;
+			return DummyDatum;
 		}
 
 		if (column_name)
@@ -4464,7 +4464,7 @@ JsonTableGetValue(TableFuncScanState *state, int colnum,
 	/* Row pattern value is NULL */
 	if (current->isnull)
 	{
-		result = (Datum) 0;
+		result = DummyDatum;
 		*isnull = true;
 	}
 	/* Evaluate JsonExpr. */
diff --git a/src/backend/utils/adt/mac.c b/src/backend/utils/adt/mac.c
index 3644e9735f5..f7efba1f61e 100644
--- a/src/backend/utils/adt/mac.c
+++ b/src/backend/utils/adt/mac.c
@@ -89,7 +89,7 @@ macaddr_in(PG_FUNCTION_ARGS)
 		count = sscanf(str, "%2x%2x%2x%2x%2x%2x%1s",
 					   &a, &b, &c, &d, &e, &f, junk);
 	if (count != 6)
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"", "macaddr",
 						str)));
@@ -97,7 +97,7 @@ macaddr_in(PG_FUNCTION_ARGS)
 	if ((a < 0) || (a > 255) || (b < 0) || (b > 255) ||
 		(c < 0) || (c > 255) || (d < 0) || (d > 255) ||
 		(e < 0) || (e > 255) || (f < 0) || (f > 255))
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("invalid octet value in \"macaddr\" value: \"%s\"", str)));
 
@@ -504,9 +504,9 @@ macaddr_abbrev_convert(Datum original, SortSupport ssup)
 		uint32		tmp;
 
 #if SIZEOF_DATUM == 8
-		tmp = (uint32) res ^ (uint32) ((uint64) res >> 32);
+		tmp = (uint32) res.value ^ (uint32) ((uint64) res.value >> 32);
 #else							/* SIZEOF_DATUM != 8 */
-		tmp = (uint32) res;
+		tmp = (uint32) res.value;
 #endif
 
 		addHyperLogLog(&uss->abbr_card, DatumGetUInt32(hash_uint32(tmp)));
@@ -520,7 +520,7 @@ macaddr_abbrev_convert(Datum original, SortSupport ssup)
 	 * comparator would have to call memcmp() with a pair of pointers to the
 	 * first byte of each abbreviated key, which is slower.
 	 */
-	res = DatumBigEndianToNative(res);
+	res.value = DatumBigEndianToNative(res);
 
 	return res;
 }
diff --git a/src/backend/utils/adt/mac8.c b/src/backend/utils/adt/mac8.c
index 08e41ba4eea..8106d5f11d4 100644
--- a/src/backend/utils/adt/mac8.c
+++ b/src/backend/utils/adt/mac8.c
@@ -221,7 +221,7 @@ macaddr8_in(PG_FUNCTION_ARGS)
 	PG_RETURN_MACADDR8_P(result);
 
 fail:
-	ereturn(escontext, (Datum) 0,
+	ereturn(escontext, DummyDatum,
 			(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 			 errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8",
 					str)));
diff --git a/src/backend/utils/adt/mcxtfuncs.c b/src/backend/utils/adt/mcxtfuncs.c
index fe6dce9cba3..df7cfd3a780 100644
--- a/src/backend/utils/adt/mcxtfuncs.c
+++ b/src/backend/utils/adt/mcxtfuncs.c
@@ -244,7 +244,7 @@ pg_get_backend_memory_contexts(PG_FUNCTION_ARGS)
 
 	hash_destroy(context_id_lookup);
 
-	return (Datum) 0;
+	return DummyDatum;
 }
 
 /*
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 6fcfd031428..61efdeb83ee 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -236,7 +236,7 @@ pg_tablespace_databases(PG_FUNCTION_ARGS)
 		ereport(WARNING,
 				(errmsg("global tablespace never has databases")));
 		/* return empty tuplestore */
-		return (Datum) 0;
+		PG_RETURN_DUMMY();
 	}
 
 	if (tablespaceOid == DEFAULTTABLESPACE_OID)
@@ -258,7 +258,7 @@ pg_tablespace_databases(PG_FUNCTION_ARGS)
 		ereport(WARNING,
 				(errmsg("%u is not a tablespace OID", tablespaceOid)));
 		/* return empty tuplestore */
-		return (Datum) 0;
+		PG_RETURN_DUMMY();
 	}
 
 	while ((de = ReadDir(dirdesc, location)) != NULL)
@@ -290,7 +290,7 @@ pg_tablespace_databases(PG_FUNCTION_ARGS)
 	}
 
 	FreeDir(dirdesc);
-	return (Datum) 0;
+	PG_RETURN_DUMMY();
 }
 
 
diff --git a/src/backend/utils/adt/multirangetypes.c b/src/backend/utils/adt/multirangetypes.c
index 097f91d2346..ef12058f542 100644
--- a/src/backend/utils/adt/multirangetypes.c
+++ b/src/backend/utils/adt/multirangetypes.c
@@ -145,7 +145,7 @@ multirange_in(PG_FUNCTION_ARGS)
 	if (*ptr == '{')
 		ptr++;
 	else
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("malformed multirange literal: \"%s\"",
 						input_str),
@@ -158,7 +158,7 @@ multirange_in(PG_FUNCTION_ARGS)
 		char		ch = *ptr;
 
 		if (ch == '\0')
-			ereturn(escontext, (Datum) 0,
+			ereturn(escontext, DummyDatum,
 					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 					 errmsg("malformed multirange literal: \"%s\"",
 							input_str),
@@ -187,7 +187,7 @@ multirange_in(PG_FUNCTION_ARGS)
 					parse_state = MULTIRANGE_AFTER_RANGE;
 				}
 				else
-					ereturn(escontext, (Datum) 0,
+					ereturn(escontext, DummyDatum,
 							(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 							 errmsg("malformed multirange literal: \"%s\"",
 									input_str),
@@ -261,7 +261,7 @@ multirange_in(PG_FUNCTION_ARGS)
 				else if (ch == '}')
 					parse_state = MULTIRANGE_FINISHED;
 				else
-					ereturn(escontext, (Datum) 0,
+					ereturn(escontext, DummyDatum,
 							(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 							 errmsg("malformed multirange literal: \"%s\"",
 									input_str),
@@ -285,7 +285,7 @@ multirange_in(PG_FUNCTION_ARGS)
 		ptr++;
 
 	if (*ptr != '\0')
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("malformed multirange literal: \"%s\"",
 						input_str),
@@ -772,7 +772,7 @@ multirange_get_bounds(TypeCacheEntry *rangetyp,
 		ptr = (Pointer) att_addlength_pointer(ptr, typlen, ptr);
 	}
 	else
-		lbound = (Datum) 0;
+		lbound = DummyDatum;
 
 	/* fetch upper bound, if any */
 	if (RANGE_HAS_UBOUND(flags))
@@ -782,7 +782,7 @@ multirange_get_bounds(TypeCacheEntry *rangetyp,
 		/* no need for att_addlength_pointer */
 	}
 	else
-		ubound = (Datum) 0;
+		ubound = DummyDatum;
 
 	/* emit results */
 	lower->val = lbound;
diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c
index 9fd211b2d45..837f5a6603d 100644
--- a/src/backend/utils/adt/network.c
+++ b/src/backend/utils/adt/network.c
@@ -643,23 +643,23 @@ network_abbrev_convert(Datum original, SortSupport ssup)
 
 		/* Must byteswap on little-endian machines */
 #ifndef WORDS_BIGENDIAN
-		ipaddr_datum = pg_bswap32(ipaddr_datum32);
+		ipaddr_datum.value = pg_bswap32(ipaddr_datum32);
 #else
-		ipaddr_datum = ipaddr_datum32;
+		ipaddr_datum.value = ipaddr_datum32;
 #endif
 
 		/* Initialize result without setting ipfamily bit */
-		res = (Datum) 0;
+		res = DummyDatum;
 	}
 	else
 	{
 		memcpy(&ipaddr_datum, ip_addr(authoritative), sizeof(Datum));
 
 		/* Must byteswap on little-endian machines */
-		ipaddr_datum = DatumBigEndianToNative(ipaddr_datum);
+		ipaddr_datum.value = DatumBigEndianToNative(ipaddr_datum);
 
 		/* Initialize result with ipfamily (most significant) bit set */
-		res = ((Datum) 1) << (SIZEOF_DATUM * BITS_PER_BYTE - 1);
+		res.value = ((uintptr_t) 1) << (SIZEOF_DATUM * BITS_PER_BYTE - 1);
 	}
 
 	/*
@@ -685,19 +685,19 @@ network_abbrev_convert(Datum original, SortSupport ssup)
 	if (ip_bits(authoritative) == 0)
 	{
 		/* Fit as many ipaddr bits as possible into subnet */
-		subnet_bitmask = ((Datum) 0) - 1;
-		network = 0;
+		subnet_bitmask.value = (DummyDatum.value) - 1;
+		network = DummyDatum;
 	}
 	else if (ip_bits(authoritative) < SIZEOF_DATUM * BITS_PER_BYTE)
 	{
 		/* Split ipaddr bits between network and subnet */
-		subnet_bitmask = (((Datum) 1) << subnet_size) - 1;
-		network = ipaddr_datum & ~subnet_bitmask;
+		subnet_bitmask.value = (1 << subnet_size) - 1;
+		network.value = ipaddr_datum.value & ~subnet_bitmask.value;
 	}
 	else
 	{
 		/* Fit as many ipaddr bits as possible into network */
-		subnet_bitmask = 0;
+		subnet_bitmask.value = 0;
 		network = ipaddr_datum;
 	}
 
@@ -708,7 +708,7 @@ network_abbrev_convert(Datum original, SortSupport ssup)
 		 * IPv4 with 8 byte datums: keep all 32 netmasked bits, netmask size,
 		 * and most significant 25 subnet bits
 		 */
-		Datum		netmask_size = (Datum) ip_bits(authoritative);
+		Datum		netmask_size = CharGetDatum(ip_bits(authoritative));
 		Datum		subnet;
 
 		/*
@@ -721,14 +721,14 @@ network_abbrev_convert(Datum original, SortSupport ssup)
 		 * ip_bits(), even though the comparison won't reach the netmask_size
 		 * bits.
 		 */
-		network <<= (ABBREV_BITS_INET4_NETMASK_SIZE +
+		network.value <<= (ABBREV_BITS_INET4_NETMASK_SIZE +
 					 ABBREV_BITS_INET4_SUBNET);
 
 		/* Shift size to make room for subnet bits at the end */
-		netmask_size <<= ABBREV_BITS_INET4_SUBNET;
+		netmask_size.value <<= ABBREV_BITS_INET4_SUBNET;
 
 		/* Extract subnet bits without shifting them */
-		subnet = ipaddr_datum & subnet_bitmask;
+		subnet.value = ipaddr_datum.value & subnet_bitmask.value;
 
 		/*
 		 * If we have more than 25 subnet bits, we can't fit everything. Shift
@@ -741,13 +741,13 @@ network_abbrev_convert(Datum original, SortSupport ssup)
 		 * get that far.
 		 */
 		if (subnet_size > ABBREV_BITS_INET4_SUBNET)
-			subnet >>= subnet_size - ABBREV_BITS_INET4_SUBNET;
+			subnet.value >>= subnet_size - ABBREV_BITS_INET4_SUBNET;
 
 		/*
 		 * Assemble the final abbreviated key without clobbering the ipfamily
 		 * bit that must remain a zero.
 		 */
-		res |= network | netmask_size | subnet;
+		res.value |= network.value | netmask_size.value | subnet.value;
 	}
 	else
 #endif
@@ -757,7 +757,7 @@ network_abbrev_convert(Datum original, SortSupport ssup)
 		 * netmasked bits as will fit in final abbreviated key. Avoid
 		 * clobbering the ipfamily bit that was set earlier.
 		 */
-		res |= network >> 1;
+		res.value |= network.value >> 1;
 	}
 
 	uss->input_count += 1;
@@ -768,9 +768,9 @@ network_abbrev_convert(Datum original, SortSupport ssup)
 		uint32		tmp;
 
 #if SIZEOF_DATUM == 8
-		tmp = (uint32) res ^ (uint32) ((uint64) res >> 32);
+		tmp = (uint32) res.value ^ (uint32) ((uint64) res.value >> 32);
 #else							/* SIZEOF_DATUM != 8 */
-		tmp = (uint32) res;
+		tmp = (uint32) res.value;
 #endif
 
 		addHyperLogLog(&uss->abbr_card, DatumGetUInt32(hash_uint32(tmp)));
diff --git a/src/backend/utils/adt/network_gist.c b/src/backend/utils/adt/network_gist.c
index a08c4953789..2f1e6feb79e 100644
--- a/src/backend/utils/adt/network_gist.c
+++ b/src/backend/utils/adt/network_gist.c
@@ -566,7 +566,7 @@ inet_gist_compress(PG_FUNCTION_ARGS)
 		}
 		else
 		{
-			gistentryinit(*retval, (Datum) 0,
+			gistentryinit(*retval, DummyDatum,
 						  entry->rel, entry->page,
 						  entry->offset, false);
 		}
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index c9233565d57..e2c50eccfc5 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -403,8 +403,8 @@ typedef struct NumericSumAccum
  */
 #define NUMERIC_ABBREV_BITS (SIZEOF_DATUM * BITS_PER_BYTE)
 #if SIZEOF_DATUM == 8
-#define NumericAbbrevGetDatum(X) ((Datum) (X))
-#define DatumGetNumericAbbrev(X) ((int64) (X))
+#define NumericAbbrevGetDatum(X) ((Datum){.value=X})
+#define DatumGetNumericAbbrev(X) ((int64) (X.value))
 #define NUMERIC_ABBREV_NAN		 NumericAbbrevGetDatum(PG_INT64_MIN)
 #define NUMERIC_ABBREV_PINF		 NumericAbbrevGetDatum(-PG_INT64_MAX)
 #define NUMERIC_ABBREV_NINF		 NumericAbbrevGetDatum(PG_INT64_MAX)
@@ -790,7 +790,7 @@ numeric_in(PG_FUNCTION_ARGS)
 		res = make_result_opt_error(&value, &have_error);
 
 		if (have_error)
-			ereturn(escontext, (Datum) 0,
+			ereturn(escontext, DummyDatum,
 					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 					 errmsg("value overflows numeric format")));
 
@@ -800,7 +800,7 @@ numeric_in(PG_FUNCTION_ARGS)
 	PG_RETURN_NUMERIC(res);
 
 invalid_syntax:
-	ereturn(escontext, (Datum) 0,
+	ereturn(escontext, DummyDatum,
 			(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 			 errmsg("invalid input syntax for type %s: \"%s\"",
 					"numeric", str)));
@@ -1528,7 +1528,7 @@ numeric_sign(PG_FUNCTION_ARGS)
 	}
 
 	Assert(false);
-	return (Datum) 0;
+	return DummyDatum;
 }
 
 
@@ -2880,7 +2880,7 @@ hash_numeric(PG_FUNCTION_ARGS)
 						  hash_len * sizeof(NumericDigit));
 
 	/* Mix in the weight, via XOR */
-	result = digit_hash ^ weight;
+	result.value = digit_hash.value ^ weight;
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/utils/adt/orderedsetaggs.c b/src/backend/utils/adt/orderedsetaggs.c
index 9457d239715..4de4699f5eb 100644
--- a/src/backend/utils/adt/orderedsetaggs.c
+++ b/src/backend/utils/adt/orderedsetaggs.c
@@ -739,7 +739,7 @@ percentile_disc_multi_final(PG_FUNCTION_ARGS)
 	Datum	   *result_datum;
 	bool	   *result_isnull;
 	int64		rownum = 0;
-	Datum		val = (Datum) 0;
+	Datum		val = DummyDatum;
 	bool		isnull = true;
 	int			i;
 
@@ -788,7 +788,7 @@ percentile_disc_multi_final(PG_FUNCTION_ARGS)
 		if (pct_info[i].first_row > 0)
 			break;
 
-		result_datum[idx] = (Datum) 0;
+		result_datum[idx] = DummyDatum;
 		result_isnull[idx] = true;
 	}
 
@@ -859,8 +859,8 @@ percentile_cont_multi_final_common(FunctionCallInfo fcinfo,
 	Datum	   *result_datum;
 	bool	   *result_isnull;
 	int64		rownum = 0;
-	Datum		first_val = (Datum) 0;
-	Datum		second_val = (Datum) 0;
+	Datum		first_val = DummyDatum;
+	Datum		second_val = DummyDatum;
 	bool		isnull;
 	int			i;
 
@@ -911,7 +911,7 @@ percentile_cont_multi_final_common(FunctionCallInfo fcinfo,
 		if (pct_info[i].first_row > 0)
 			break;
 
-		result_datum[idx] = (Datum) 0;
+		result_datum[idx] = DummyDatum;
 		result_isnull[idx] = true;
 	}
 
@@ -1035,14 +1035,14 @@ mode_final(PG_FUNCTION_ARGS)
 	OSAPerGroupState *osastate;
 	Datum		val;
 	bool		isnull;
-	Datum		mode_val = (Datum) 0;
+	Datum		mode_val = DummyDatum;
 	int64		mode_freq = 0;
-	Datum		last_val = (Datum) 0;
+	Datum		last_val = DummyDatum;
 	int64		last_val_freq = 0;
 	bool		last_val_is_mode = false;
 	FmgrInfo   *equalfn;
-	Datum		abbrev_val = (Datum) 0;
-	Datum		last_abbrev_val = (Datum) 0;
+	Datum		abbrev_val = DummyDatum;
+	Datum		last_abbrev_val = DummyDatum;
 	bool		shouldfree;
 
 	Assert(AggCheckCallContext(fcinfo, NULL) == AGG_CONTEXT_AGGREGATE);
@@ -1090,7 +1090,7 @@ mode_final(PG_FUNCTION_ARGS)
 			last_val_is_mode = true;
 			last_abbrev_val = abbrev_val;
 		}
-		else if (abbrev_val == last_abbrev_val &&
+		else if (abbrev_val.value == last_abbrev_val.value &&
 				 DatumGetBool(FunctionCall2Coll(equalfn, PG_GET_COLLATION(), val, last_val)))
 		{
 			/* value equal to previous value, count it */
@@ -1301,8 +1301,8 @@ hypothetical_dense_rank_final(PG_FUNCTION_ARGS)
 	int64		duplicate_count = 0;
 	OSAPerGroupState *osastate;
 	int			numDistinctCols;
-	Datum		abbrevVal = (Datum) 0;
-	Datum		abbrevOld = (Datum) 0;
+	Datum		abbrevVal = DummyDatum;
+	Datum		abbrevOld = DummyDatum;
 	TupleTableSlot *slot;
 	TupleTableSlot *extraslot;
 	TupleTableSlot *slot2;
@@ -1404,7 +1404,7 @@ hypothetical_dense_rank_final(PG_FUNCTION_ARGS)
 		econtext->ecxt_innertuple = slot2;
 
 		if (!TupIsNull(slot2) &&
-			abbrevVal == abbrevOld &&
+			abbrevVal.value == abbrevOld.value &&
 			ExecQualAndReset(compareTuple, econtext))
 			duplicate_count++;
 
diff --git a/src/backend/utils/adt/pg_lsn.c b/src/backend/utils/adt/pg_lsn.c
index 12de2446f5b..ea4af20c443 100644
--- a/src/backend/utils/adt/pg_lsn.c
+++ b/src/backend/utils/adt/pg_lsn.c
@@ -68,7 +68,7 @@ pg_lsn_in(PG_FUNCTION_ARGS)
 
 	result = pg_lsn_in_internal(str, &have_error);
 	if (have_error)
-		ereturn(fcinfo->context, (Datum) 0,
+		ereturn(fcinfo->context, DummyDatum,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"pg_lsn", str)));
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 1c12ddbae49..b8243b2f64e 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -321,7 +321,7 @@ pg_stat_get_progress_info(PG_FUNCTION_ARGS)
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
 
-	return (Datum) 0;
+	return DummyDatum;
 }
 
 /*
@@ -682,7 +682,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 			break;
 	}
 
-	return (Datum) 0;
+	return DummyDatum;
 }
 
 
@@ -1567,7 +1567,7 @@ pg_stat_get_io(PG_FUNCTION_ARGS)
 								backends_io_stats->stat_reset_timestamp);
 	}
 
-	return (Datum) 0;
+	return DummyDatum;
 }
 
 /*
@@ -1589,7 +1589,7 @@ pg_stat_get_backend_io(PG_FUNCTION_ARGS)
 	backend_stats = pgstat_fetch_stat_backend_by_pid(pid, &bktype);
 
 	if (!backend_stats)
-		return (Datum) 0;
+		return DummyDatum;
 
 	bktype_stats = &backend_stats->io_stats;
 
@@ -1603,7 +1603,7 @@ pg_stat_get_backend_io(PG_FUNCTION_ARGS)
 	/* save tuples with data from this PgStat_BktypeIO */
 	pg_stat_io_build_tuples(rsinfo, bktype_stats, bktype,
 							backend_stats->stat_reset_timestamp);
-	return (Datum) 0;
+	return DummyDatum;
 }
 
 /*
@@ -1740,7 +1740,7 @@ pg_stat_get_slru(PG_FUNCTION_ARGS)
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
 
-	return (Datum) 0;
+	return DummyDatum;
 }
 
 #define PG_STAT_GET_XACT_RELENTRY_INT64(stat)			\
diff --git a/src/backend/utils/adt/rangetypes.c b/src/backend/utils/adt/rangetypes.c
index 15398c72ea0..fd8d6b7172d 100644
--- a/src/backend/utils/adt/rangetypes.c
+++ b/src/backend/utils/adt/rangetypes.c
@@ -222,7 +222,7 @@ range_recv(PG_FUNCTION_ARGS)
 		pfree(bound_buf.data);
 	}
 	else
-		lower.val = (Datum) 0;
+		lower.val = DummyDatum;
 
 	if (RANGE_HAS_UBOUND(flags))
 	{
@@ -240,7 +240,7 @@ range_recv(PG_FUNCTION_ARGS)
 		pfree(bound_buf.data);
 	}
 	else
-		upper.val = (Datum) 0;
+		upper.val = DummyDatum;
 
 	pq_getmsgend(buf);
 
@@ -386,12 +386,12 @@ range_constructor2(PG_FUNCTION_ARGS)
 
 	typcache = range_get_typcache(fcinfo, rngtypid);
 
-	lower.val = PG_ARGISNULL(0) ? (Datum) 0 : arg1;
+	lower.val = PG_ARGISNULL(0) ? DummyDatum : arg1;
 	lower.infinite = PG_ARGISNULL(0);
 	lower.inclusive = true;
 	lower.lower = true;
 
-	upper.val = PG_ARGISNULL(1) ? (Datum) 0 : arg2;
+	upper.val = PG_ARGISNULL(1) ? DummyDatum : arg2;
 	upper.infinite = PG_ARGISNULL(1);
 	upper.inclusive = false;
 	upper.lower = false;
@@ -423,12 +423,12 @@ range_constructor3(PG_FUNCTION_ARGS)
 
 	flags = range_parse_flags(text_to_cstring(PG_GETARG_TEXT_PP(2)));
 
-	lower.val = PG_ARGISNULL(0) ? (Datum) 0 : arg1;
+	lower.val = PG_ARGISNULL(0) ? DummyDatum : arg1;
 	lower.infinite = PG_ARGISNULL(0);
 	lower.inclusive = (flags & RANGE_LB_INC) != 0;
 	lower.lower = true;
 
-	upper.val = PG_ARGISNULL(1) ? (Datum) 0 : arg2;
+	upper.val = PG_ARGISNULL(1) ? DummyDatum : arg2;
 	upper.infinite = PG_ARGISNULL(1);
 	upper.inclusive = (flags & RANGE_UB_INC) != 0;
 	upper.lower = false;
@@ -1343,9 +1343,9 @@ range_fast_cmp(Datum a, Datum b, SortSupport ssup)
 			cmp = range_cmp_bounds(typcache, &upper1, &upper2);
 	}
 
-	if ((Datum) range_a != a)
+	if (PointerGetDatum(range_a).value != a.value)
 		pfree(range_a);
-	if ((Datum) range_b != b)
+	if (PointerGetDatum(range_b).value != b.value)
 		pfree(range_b);
 
 	return cmp;
@@ -1545,7 +1545,7 @@ int4range_canonical(PG_FUNCTION_ARGS)
 
 		/* Handle possible overflow manually */
 		if (unlikely(bnd == PG_INT32_MAX))
-			ereturn(escontext, (Datum) 0,
+			ereturn(escontext, DummyDatum,
 					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 					 errmsg("integer out of range")));
 		lower.val = Int32GetDatum(bnd + 1);
@@ -1558,7 +1558,7 @@ int4range_canonical(PG_FUNCTION_ARGS)
 
 		/* Handle possible overflow manually */
 		if (unlikely(bnd == PG_INT32_MAX))
-			ereturn(escontext, (Datum) 0,
+			ereturn(escontext, DummyDatum,
 					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 					 errmsg("integer out of range")));
 		upper.val = Int32GetDatum(bnd + 1);
@@ -1592,7 +1592,7 @@ int8range_canonical(PG_FUNCTION_ARGS)
 
 		/* Handle possible overflow manually */
 		if (unlikely(bnd == PG_INT64_MAX))
-			ereturn(escontext, (Datum) 0,
+			ereturn(escontext, DummyDatum,
 					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 					 errmsg("bigint out of range")));
 		lower.val = Int64GetDatum(bnd + 1);
@@ -1605,7 +1605,7 @@ int8range_canonical(PG_FUNCTION_ARGS)
 
 		/* Handle possible overflow manually */
 		if (unlikely(bnd == PG_INT64_MAX))
-			ereturn(escontext, (Datum) 0,
+			ereturn(escontext, DummyDatum,
 					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 					 errmsg("bigint out of range")));
 		upper.val = Int64GetDatum(bnd + 1);
@@ -1641,7 +1641,7 @@ daterange_canonical(PG_FUNCTION_ARGS)
 		/* Check for overflow -- note we already eliminated PG_INT32_MAX */
 		bnd++;
 		if (unlikely(!IS_VALID_DATE(bnd)))
-			ereturn(escontext, (Datum) 0,
+			ereturn(escontext, DummyDatum,
 					(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
 					 errmsg("date out of range")));
 		lower.val = DateADTGetDatum(bnd);
@@ -1656,7 +1656,7 @@ daterange_canonical(PG_FUNCTION_ARGS)
 		/* Check for overflow -- note we already eliminated PG_INT32_MAX */
 		bnd++;
 		if (unlikely(!IS_VALID_DATE(bnd)))
-			ereturn(escontext, (Datum) 0,
+			ereturn(escontext, DummyDatum,
 					(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
 					 errmsg("date out of range")));
 		upper.val = DateADTGetDatum(bnd);
@@ -1948,7 +1948,7 @@ range_deserialize(TypeCacheEntry *typcache, const RangeType *range,
 		ptr = (Pointer) att_addlength_pointer(ptr, typlen, ptr);
 	}
 	else
-		lbound = (Datum) 0;
+		lbound = DummyDatum;
 
 	/* fetch upper bound, if any */
 	if (RANGE_HAS_UBOUND(flags))
@@ -1958,7 +1958,7 @@ range_deserialize(TypeCacheEntry *typcache, const RangeType *range,
 		/* no need for att_addlength_pointer */
 	}
 	else
-		ubound = (Datum) 0;
+		ubound = DummyDatum;
 
 	/* emit results */
 
@@ -2229,12 +2229,12 @@ make_empty_range(TypeCacheEntry *typcache)
 	RangeBound	lower;
 	RangeBound	upper;
 
-	lower.val = (Datum) 0;
+	lower.val = DummyDatum;
 	lower.infinite = false;
 	lower.inclusive = false;
 	lower.lower = true;
 
-	upper.val = (Datum) 0;
+	upper.val = DummyDatum;
 	upper.infinite = false;
 	upper.inclusive = false;
 	upper.lower = false;
diff --git a/src/backend/utils/adt/regexp.c b/src/backend/utils/adt/regexp.c
index 6e2864cbbda..772a52d7d90 100644
--- a/src/backend/utils/adt/regexp.c
+++ b/src/backend/utils/adt/regexp.c
@@ -1662,7 +1662,7 @@ build_regexp_match_result(regexp_matches_ctx *matchctx)
 
 		if (so < 0 || eo < 0)
 		{
-			elems[i] = (Datum) 0;
+			elems[i] = DummyDatum;
 			nulls[i] = true;
 		}
 		else if (buf)
diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c
index b8bbe95e82e..5518404a186 100644
--- a/src/backend/utils/adt/regproc.c
+++ b/src/backend/utils/adt/regproc.c
@@ -96,11 +96,11 @@ regprocin(PG_FUNCTION_ARGS)
 	clist = FuncnameGetCandidates(names, -1, NIL, false, false, false, true);
 
 	if (clist == NULL)
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_UNDEFINED_FUNCTION),
 				 errmsg("function \"%s\" does not exist", pro_name_or_oid)));
 	else if (clist->next != NULL)
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_AMBIGUOUS_FUNCTION),
 				 errmsg("more than one function named \"%s\"",
 						pro_name_or_oid)));
@@ -261,7 +261,7 @@ regprocedurein(PG_FUNCTION_ARGS)
 	}
 
 	if (clist == NULL)
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_UNDEFINED_FUNCTION),
 				 errmsg("function \"%s\" does not exist", pro_name_or_oid)));
 
@@ -505,11 +505,11 @@ regoperin(PG_FUNCTION_ARGS)
 	clist = OpernameGetCandidates(names, '\0', true);
 
 	if (clist == NULL)
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_UNDEFINED_FUNCTION),
 				 errmsg("operator does not exist: %s", opr_name_or_oid)));
 	else if (clist->next != NULL)
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_AMBIGUOUS_FUNCTION),
 				 errmsg("more than one operator named %s",
 						opr_name_or_oid)));
@@ -666,12 +666,12 @@ regoperatorin(PG_FUNCTION_ARGS)
 		PG_RETURN_NULL();
 
 	if (nargs == 1)
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_UNDEFINED_PARAMETER),
 				 errmsg("missing argument"),
 				 errhint("Use NONE to denote the missing argument of a unary operator.")));
 	if (nargs != 2)
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_TOO_MANY_ARGUMENTS),
 				 errmsg("too many arguments"),
 				 errhint("Provide two argument types for operator.")));
@@ -679,7 +679,7 @@ regoperatorin(PG_FUNCTION_ARGS)
 	result = OpernameGetOprid(names, argtypes[0], argtypes[1]);
 
 	if (!OidIsValid(result))
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_UNDEFINED_FUNCTION),
 				 errmsg("operator does not exist: %s", opr_name_or_oid)));
 
@@ -909,7 +909,7 @@ regclassin(PG_FUNCTION_ARGS)
 	result = RangeVarGetRelid(makeRangeVarFromNameList(names), NoLock, true);
 
 	if (!OidIsValid(result))
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_UNDEFINED_TABLE),
 				 errmsg("relation \"%s\" does not exist",
 						NameListToString(names))));
@@ -1052,7 +1052,7 @@ regcollationin(PG_FUNCTION_ARGS)
 	result = get_collation_oid(names, true);
 
 	if (!OidIsValid(result))
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
 				 errmsg("collation \"%s\" for encoding \"%s\" does not exist",
 						NameListToString(names), GetDatabaseEncodingName())));
@@ -1345,7 +1345,7 @@ regconfigin(PG_FUNCTION_ARGS)
 	result = get_ts_config_oid(names, true);
 
 	if (!OidIsValid(result))
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
 				 errmsg("text search configuration \"%s\" does not exist",
 						NameListToString(names))));
@@ -1455,7 +1455,7 @@ regdictionaryin(PG_FUNCTION_ARGS)
 	result = get_ts_dict_oid(names, true);
 
 	if (!OidIsValid(result))
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
 				 errmsg("text search dictionary \"%s\" does not exist",
 						NameListToString(names))));
@@ -1560,14 +1560,14 @@ regrolein(PG_FUNCTION_ARGS)
 		PG_RETURN_NULL();
 
 	if (list_length(names) != 1)
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_INVALID_NAME),
 				 errmsg("invalid name syntax")));
 
 	result = get_role_oid(strVal(linitial(names)), true);
 
 	if (!OidIsValid(result))
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
 				 errmsg("role \"%s\" does not exist",
 						strVal(linitial(names)))));
@@ -1677,14 +1677,14 @@ regnamespacein(PG_FUNCTION_ARGS)
 		PG_RETURN_NULL();
 
 	if (list_length(names) != 1)
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_INVALID_NAME),
 				 errmsg("invalid name syntax")));
 
 	result = get_namespace_oid(strVal(linitial(names)), true);
 
 	if (!OidIsValid(result))
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_UNDEFINED_SCHEMA),
 				 errmsg("schema \"%s\" does not exist",
 						strVal(linitial(names)))));
@@ -1794,14 +1794,14 @@ regdatabasein(PG_FUNCTION_ARGS)
 		PG_RETURN_NULL();
 
 	if (list_length(names) != 1)
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_INVALID_NAME),
 				 errmsg("invalid name syntax")));
 
 	result = get_database_oid(strVal(linitial(names)), true);
 
 	if (!OidIsValid(result))
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
 				 errmsg("database \"%s\" does not exist",
 						strVal(linitial(names)))));
diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c
index 059fc5ebf60..2f1f8ad50b9 100644
--- a/src/backend/utils/adt/ri_triggers.c
+++ b/src/backend/utils/adt/ri_triggers.c
@@ -2868,7 +2868,7 @@ ri_InitHashTables(void)
 	/* Arrange to flush cache on pg_constraint changes */
 	CacheRegisterSyscacheCallback(CONSTROID,
 								  InvalidateConstraintCacheCallBack,
-								  (Datum) 0);
+								  DummyDatum);
 
 	ctl.keysize = sizeof(RI_QueryKey);
 	ctl.entrysize = sizeof(RI_QueryHashEntry);
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 9e5449f17d7..8dfca44c669 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -100,7 +100,7 @@ record_in(PG_FUNCTION_ARGS)
 	 * supply a valid typmod, and then we can do something useful for RECORD.
 	 */
 	if (tupType == RECORDOID && tupTypmod < 0)
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("input of anonymous composite types is not implemented")));
 
@@ -172,7 +172,7 @@ record_in(PG_FUNCTION_ARGS)
 		/* Ignore dropped columns in datatype, but fill with nulls */
 		if (att->attisdropped)
 		{
-			values[i] = (Datum) 0;
+			values[i] = DummyDatum;
 			nulls[i] = true;
 			continue;
 		}
@@ -572,7 +572,7 @@ record_recv(PG_FUNCTION_ARGS)
 		/* Ignore dropped columns in datatype, but fill with nulls */
 		if (att->attisdropped)
 		{
-			values[i] = (Datum) 0;
+			values[i] = DummyDatum;
 			nulls[i] = true;
 			continue;
 		}
@@ -1502,8 +1502,8 @@ record_image_cmp(FunctionCallInfo fcinfo)
 			/* Compare the pair of elements */
 			if (att1->attbyval)
 			{
-				if (values1[i1] != values2[i2])
-					cmpresult = (values1[i1] < values2[i2]) ? -1 : 1;
+				if (values1[i1].value != values2[i2].value)
+					cmpresult = (values1[i1].value < values2[i2].value) ? -1 : 1;
 			}
 			else if (att1->attlen > 0)
 			{
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 3d6e6bdbfd2..53ee62f827a 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -1462,7 +1462,7 @@ pg_get_indexdef_worker(Oid indexrelid, int colno,
 			int16		opt = indoption->values[keyno];
 			Oid			indcoll = indcollation->values[keyno];
 			Datum		attoptions = get_attoptions(indexrelid, keyno + 1);
-			bool		has_options = attoptions != (Datum) 0;
+			bool		has_options = attoptions.value != DummyDatum.value;
 
 			/* Add collation, if not default for column */
 			if (OidIsValid(indcoll) && indcoll != keycolcollation)
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 17fbfa9b410..d799479bf18 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -6292,8 +6292,8 @@ get_variable_range(PlannerInfo *root, VariableStatData *vardata,
 				   Oid sortop, Oid collation,
 				   Datum *min, Datum *max)
 {
-	Datum		tmin = 0;
-	Datum		tmax = 0;
+	Datum		tmin = DummyDatum;
+	Datum		tmax = DummyDatum;
 	bool		have_data = false;
 	int16		typLen;
 	bool		typByVal;
@@ -6590,7 +6590,7 @@ get_actual_variable_range(PlannerInfo *root, VariableStatData *vardata,
 								   InvalidOid,	/* no strategy subtype */
 								   InvalidOid,	/* no collation */
 								   InvalidOid,	/* no reg proc for this */
-								   (Datum) 0);	/* constant */
+								   DummyDatum);	/* constant */
 
 			/* If min is requested ... */
 			if (min)
diff --git a/src/backend/utils/adt/tid.c b/src/backend/utils/adt/tid.c
index 39dab3e42df..b9a87d3173c 100644
--- a/src/backend/utils/adt/tid.c
+++ b/src/backend/utils/adt/tid.c
@@ -67,7 +67,7 @@ tidin(PG_FUNCTION_ARGS)
 			coord[i++] = p + 1;
 
 	if (i < NTIDARGS)
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"tid", str)));
@@ -75,7 +75,7 @@ tidin(PG_FUNCTION_ARGS)
 	errno = 0;
 	cvt = strtoul(coord[0], &badp, 10);
 	if (errno || *badp != DELIM)
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"tid", str)));
@@ -89,7 +89,7 @@ tidin(PG_FUNCTION_ARGS)
 #if SIZEOF_LONG > 4
 	if (cvt != (unsigned long) blockNumber &&
 		cvt != (unsigned long) ((int32) blockNumber))
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"tid", str)));
@@ -98,7 +98,7 @@ tidin(PG_FUNCTION_ARGS)
 	cvt = strtoul(coord[1], &badp, 10);
 	if (errno || *badp != RDELIM ||
 		cvt > USHRT_MAX)
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for type %s: \"%s\"",
 						"tid", str)));
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index e640b48205b..3fb9a17eb03 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -199,7 +199,7 @@ timestamp_in(PG_FUNCTION_ARGS)
 	{
 		case DTK_DATE:
 			if (tm2timestamp(tm, fsec, NULL, &result) != 0)
-				ereturn(escontext, (Datum) 0,
+				ereturn(escontext, DummyDatum,
 						(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
 						 errmsg("timestamp out of range: \"%s\"", str)));
 			break;
@@ -452,7 +452,7 @@ timestamptz_in(PG_FUNCTION_ARGS)
 	{
 		case DTK_DATE:
 			if (tm2timestamp(tm, fsec, &tz, &result) != 0)
-				ereturn(escontext, (Datum) 0,
+				ereturn(escontext, DummyDatum,
 						(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
 						 errmsg("timestamp out of range: \"%s\"", str)));
 			break;
@@ -943,7 +943,7 @@ interval_in(PG_FUNCTION_ARGS)
 	{
 		case DTK_DELTA:
 			if (itmin2interval(itm_in, result) != 0)
-				ereturn(escontext, (Datum) 0,
+				ereturn(escontext, DummyDatum,
 						(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
 						 errmsg("interval out of range")));
 			break;
@@ -2315,7 +2315,7 @@ timestamp_decrement(Relation rel, Datum existing, bool *underflow)
 	{
 		/* return value is undefined */
 		*underflow = true;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 
 	*underflow = false;
@@ -2332,7 +2332,7 @@ timestamp_increment(Relation rel, Datum existing, bool *overflow)
 	{
 		/* return value is undefined */
 		*overflow = true;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 
 	*overflow = false;
diff --git a/src/backend/utils/adt/tsvector.c b/src/backend/utils/adt/tsvector.c
index 1fa2e3729bf..9c84584bcef 100644
--- a/src/backend/utils/adt/tsvector.c
+++ b/src/backend/utils/adt/tsvector.c
@@ -208,14 +208,14 @@ tsvectorin(PG_FUNCTION_ARGS)
 	while (gettoken_tsvector(state, &token, &toklen, &pos, &poslen, NULL))
 	{
 		if (toklen >= MAXSTRLEN)
-			ereturn(escontext, (Datum) 0,
+			ereturn(escontext, DummyDatum,
 					(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
 					 errmsg("word is too long (%ld bytes, max %ld bytes)",
 							(long) toklen,
 							(long) (MAXSTRLEN - 1))));
 
 		if (cur - tmpbuf > MAXSTRPOS)
-			ereturn(escontext, (Datum) 0,
+			ereturn(escontext, DummyDatum,
 					(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
 					 errmsg("string is too long for tsvector (%ld bytes, max %ld bytes)",
 							(long) (cur - tmpbuf), (long) MAXSTRPOS)));
@@ -269,7 +269,7 @@ tsvectorin(PG_FUNCTION_ARGS)
 		buflen = 0;
 
 	if (buflen > MAXSTRPOS)
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
 				 errmsg("string is too long for tsvector (%d bytes, max %d bytes)", buflen, MAXSTRPOS)));
 
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 0625da9532f..fb2cd1206a4 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -2568,7 +2568,7 @@ ts_process_call(FuncCallContext *funcctx)
 		return result;
 	}
 
-	return (Datum) 0;
+	return DummyDatum;
 }
 
 static TSVectorStat *
@@ -2680,7 +2680,8 @@ ts_stat1(PG_FUNCTION_ARGS)
 	}
 
 	funcctx = SRF_PERCALL_SETUP();
-	if ((result = ts_process_call(funcctx)) != (Datum) 0)
+	result = ts_process_call(funcctx);
+	if (result.value != DummyDatum.value)
 		SRF_RETURN_NEXT(funcctx, result);
 	SRF_RETURN_DONE(funcctx);
 }
@@ -2707,7 +2708,8 @@ ts_stat2(PG_FUNCTION_ARGS)
 	}
 
 	funcctx = SRF_PERCALL_SETUP();
-	if ((result = ts_process_call(funcctx)) != (Datum) 0)
+	result = ts_process_call(funcctx);
+	if (result.value != DummyDatum.value)
 		SRF_RETURN_NEXT(funcctx, result);
 	SRF_RETURN_DONE(funcctx);
 }
diff --git a/src/backend/utils/adt/uuid.c b/src/backend/utils/adt/uuid.c
index bce7309c183..2203400de79 100644
--- a/src/backend/utils/adt/uuid.c
+++ b/src/backend/utils/adt/uuid.c
@@ -399,9 +399,9 @@ uuid_abbrev_convert(Datum original, SortSupport ssup)
 		uint32		tmp;
 
 #if SIZEOF_DATUM == 8
-		tmp = (uint32) res ^ (uint32) ((uint64) res >> 32);
+		tmp = (uint32) res.value ^ (uint32) ((uint64) res.value >> 32);
 #else							/* SIZEOF_DATUM != 8 */
-		tmp = (uint32) res;
+		tmp = (uint32) res.value;
 #endif
 
 		addHyperLogLog(&uss->abbr_card, DatumGetUInt32(hash_uint32(tmp)));
@@ -415,7 +415,7 @@ uuid_abbrev_convert(Datum original, SortSupport ssup)
 	 * this, the comparator would have to call memcmp() with a pair of
 	 * pointers to the first byte of each abbreviated key, which is slower.
 	 */
-	res = DatumBigEndianToNative(res);
+	res.value = DatumBigEndianToNative(res);
 
 	return res;
 }
@@ -442,7 +442,7 @@ uuid_decrement(Relation rel, Datum existing, bool *underflow)
 
 	/* return value is undefined */
 	*underflow = true;
-	return (Datum) 0;
+	return DummyDatum;
 }
 
 static Datum
@@ -467,7 +467,7 @@ uuid_increment(Relation rel, Datum existing, bool *overflow)
 
 	/* return value is undefined */
 	*overflow = true;
-	return (Datum) 0;
+	return DummyDatum;
 }
 
 Datum
diff --git a/src/backend/utils/adt/varbit.c b/src/backend/utils/adt/varbit.c
index 205a67dafc5..6ba42a6a48c 100644
--- a/src/backend/utils/adt/varbit.c
+++ b/src/backend/utils/adt/varbit.c
@@ -193,7 +193,7 @@ bit_in(PG_FUNCTION_ARGS)
 	else
 	{
 		if (slen > VARBITMAXLEN / 4)
-			ereturn(escontext, (Datum) 0,
+			ereturn(escontext, DummyDatum,
 					(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
 					 errmsg("bit string length exceeds the maximum allowed (%d)",
 							VARBITMAXLEN)));
@@ -207,7 +207,7 @@ bit_in(PG_FUNCTION_ARGS)
 	if (atttypmod <= 0)
 		atttypmod = bitlen;
 	else if (bitlen != atttypmod)
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_STRING_DATA_LENGTH_MISMATCH),
 				 errmsg("bit string length %d does not match type bit(%d)",
 						bitlen, atttypmod)));
@@ -229,7 +229,7 @@ bit_in(PG_FUNCTION_ARGS)
 			if (*sp == '1')
 				*r |= x;
 			else if (*sp != '0')
-				ereturn(escontext, (Datum) 0,
+				ereturn(escontext, DummyDatum,
 						(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 						 errmsg("\"%.*s\" is not a valid binary digit",
 								pg_mblen(sp), sp)));
@@ -254,7 +254,7 @@ bit_in(PG_FUNCTION_ARGS)
 			else if (*sp >= 'a' && *sp <= 'f')
 				x = (bits8) (*sp - 'a') + 10;
 			else
-				ereturn(escontext, (Datum) 0,
+				ereturn(escontext, DummyDatum,
 						(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 						 errmsg("\"%.*s\" is not a valid hexadecimal digit",
 								pg_mblen(sp), sp)));
@@ -494,7 +494,7 @@ varbit_in(PG_FUNCTION_ARGS)
 	else
 	{
 		if (slen > VARBITMAXLEN / 4)
-			ereturn(escontext, (Datum) 0,
+			ereturn(escontext, DummyDatum,
 					(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
 					 errmsg("bit string length exceeds the maximum allowed (%d)",
 							VARBITMAXLEN)));
@@ -508,7 +508,7 @@ varbit_in(PG_FUNCTION_ARGS)
 	if (atttypmod <= 0)
 		atttypmod = bitlen;
 	else if (bitlen > atttypmod)
-		ereturn(escontext, (Datum) 0,
+		ereturn(escontext, DummyDatum,
 				(errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
 				 errmsg("bit string too long for type bit varying(%d)",
 						atttypmod)));
@@ -530,7 +530,7 @@ varbit_in(PG_FUNCTION_ARGS)
 			if (*sp == '1')
 				*r |= x;
 			else if (*sp != '0')
-				ereturn(escontext, (Datum) 0,
+				ereturn(escontext, DummyDatum,
 						(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 						 errmsg("\"%.*s\" is not a valid binary digit",
 								pg_mblen(sp), sp)));
@@ -555,7 +555,7 @@ varbit_in(PG_FUNCTION_ARGS)
 			else if (*sp >= 'a' && *sp <= 'f')
 				x = (bits8) (*sp - 'a') + 10;
 			else
-				ereturn(escontext, (Datum) 0,
+				ereturn(escontext, DummyDatum,
 						(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 						 errmsg("\"%.*s\" is not a valid hexadecimal digit",
 								pg_mblen(sp), sp)));
diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c
index 11b442a5941..60dde5a30ef 100644
--- a/src/backend/utils/adt/varlena.c
+++ b/src/backend/utils/adt/varlena.c
@@ -1770,9 +1770,9 @@ varstrfastcmp_c(Datum x, Datum y, SortSupport ssup)
 		result = (len1 < len2) ? -1 : 1;
 
 	/* We can't afford to leak memory here. */
-	if (PointerGetDatum(arg1) != x)
+	if (PointerGetDatum(arg1).value != x.value)
 		pfree(arg1);
-	if (PointerGetDatum(arg2) != y)
+	if (PointerGetDatum(arg2).value != y.value)
 		pfree(arg2);
 
 	return result;
@@ -1807,9 +1807,9 @@ bpcharfastcmp_c(Datum x, Datum y, SortSupport ssup)
 		result = (len1 < len2) ? -1 : 1;
 
 	/* We can't afford to leak memory here. */
-	if (PointerGetDatum(arg1) != x)
+	if (PointerGetDatum(arg1).value != x.value)
 		pfree(arg1);
-	if (PointerGetDatum(arg2) != y)
+	if (PointerGetDatum(arg2).value != y.value)
 		pfree(arg2);
 
 	return result;
@@ -1850,9 +1850,9 @@ varlenafastcmp_locale(Datum x, Datum y, SortSupport ssup)
 	result = varstrfastcmp_locale(a1p, len1, a2p, len2, ssup);
 
 	/* We can't afford to leak memory here. */
-	if (PointerGetDatum(arg1) != x)
+	if (PointerGetDatum(arg1).value != x.value)
 		pfree(arg1);
-	if (PointerGetDatum(arg2) != y)
+	if (PointerGetDatum(arg2).value != y.value)
 		pfree(arg2);
 
 	return result;
@@ -2137,8 +2137,8 @@ varstr_abbrev_convert(Datum original, SortSupport ssup)
 		uint32		lohalf,
 					hihalf;
 
-		lohalf = (uint32) res;
-		hihalf = (uint32) (res >> 32);
+		lohalf = (uint32) res.value;
+		hihalf = (uint32) (res.value >> 32);
 		hash = DatumGetUInt32(hash_uint32(lohalf ^ hihalf));
 	}
 #else							/* SIZEOF_DATUM != 8 */
@@ -2159,10 +2159,10 @@ varstr_abbrev_convert(Datum original, SortSupport ssup)
 	 * this, the comparator would have to call memcmp() with a pair of
 	 * pointers to the first byte of each abbreviated key, which is slower.
 	 */
-	res = DatumBigEndianToNative(res);
+	res.value = DatumBigEndianToNative(res);
 
 	/* Don't leak memory here */
-	if (PointerGetDatum(authoritative) != original)
+	if (PointerGetDatum(authoritative).value != original.value)
 		pfree(authoritative);
 
 	return res;
@@ -3663,7 +3663,7 @@ text_to_table(PG_FUNCTION_ARGS)
 
 	(void) split_text(fcinfo, &tstate);
 
-	return (Datum) 0;
+	return DummyDatum;
 }
 
 /*
diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c
index 182e8f75db7..761b0f764d1 100644
--- a/src/backend/utils/adt/xml.c
+++ b/src/backend/utils/adt/xml.c
@@ -293,7 +293,7 @@ xml_in(PG_FUNCTION_ARGS)
 	PG_RETURN_XML_P(vardata);
 #else
 	NO_XML_SUPPORT();
-	return 0;
+	return DummyDatum;
 #endif
 }
 
@@ -429,7 +429,7 @@ xml_recv(PG_FUNCTION_ARGS)
 	PG_RETURN_XML_P(result);
 #else
 	NO_XML_SUPPORT();
-	return 0;
+	return DummyDatum;
 #endif
 }
 
@@ -518,7 +518,7 @@ xmlcomment(PG_FUNCTION_ARGS)
 	PG_RETURN_XML_P(stringinfo_to_xmltype(&buf));
 #else
 	NO_XML_SUPPORT();
-	return 0;
+	return DummyDatum;
 #endif
 }
 
@@ -562,7 +562,7 @@ xmltext(PG_FUNCTION_ARGS)
 	PG_RETURN_XML_P(result);
 #else
 	NO_XML_SUPPORT();
-	return 0;
+	return DummyDatum;
 #endif							/* not USE_LIBXML */
 }
 
@@ -1160,7 +1160,7 @@ xmlvalidate(PG_FUNCTION_ARGS)
 	ereport(ERROR,
 			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 			 errmsg("xmlvalidate is not implemented")));
-	return 0;
+	PG_RETURN_DUMMY();
 }
 
 
@@ -4578,7 +4578,7 @@ xpath(PG_FUNCTION_ARGS)
 	PG_RETURN_DATUM(makeArrayResult(astate, CurrentMemoryContext));
 #else
 	NO_XML_SUPPORT();
-	return 0;
+	return DummyDatum;
 #endif
 }
 
@@ -4600,7 +4600,7 @@ xmlexists(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(res_nitems > 0);
 #else
 	NO_XML_SUPPORT();
-	return 0;
+	return DummyDatum;
 #endif
 }
 
@@ -4624,7 +4624,7 @@ xpath_exists(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(res_nitems > 0);
 #else
 	NO_XML_SUPPORT();
-	return 0;
+	return DummyDatum;
 #endif
 }
 
@@ -4660,7 +4660,7 @@ xml_is_well_formed(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(wellformed_xml(data, xmloption));
 #else
 	NO_XML_SUPPORT();
-	return 0;
+	return DummyDatum;
 #endif							/* not USE_LIBXML */
 }
 
@@ -4673,7 +4673,7 @@ xml_is_well_formed_document(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(wellformed_xml(data, XMLOPTION_DOCUMENT));
 #else
 	NO_XML_SUPPORT();
-	return 0;
+	return DummyDatum;
 #endif							/* not USE_LIBXML */
 }
 
@@ -4686,7 +4686,7 @@ xml_is_well_formed_content(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(wellformed_xml(data, XMLOPTION_CONTENT));
 #else
 	NO_XML_SUPPORT();
-	return 0;
+	return DummyDatum;
 #endif							/* not USE_LIBXML */
 }
 
@@ -4974,7 +4974,7 @@ XmlTableGetValue(TableFuncScanState *state, int colnum,
 				 Oid typid, int32 typmod, bool *isnull)
 {
 #ifdef USE_LIBXML
-	Datum		result = (Datum) 0;
+	Datum		result = DummyDatum;
 	XmlTableBuilderData *xtCxt;
 	volatile xmlXPathObjectPtr xpathobj = NULL;
 
@@ -5113,7 +5113,7 @@ XmlTableGetValue(TableFuncScanState *state, int colnum,
 	return result;
 #else
 	NO_XML_SUPPORT();
-	return 0;
+	return DummyDatum;
 #endif							/* not USE_LIBXML */
 }
 
diff --git a/src/backend/utils/cache/attoptcache.c b/src/backend/utils/cache/attoptcache.c
index 45d1e2be007..bf5c702a5cd 100644
--- a/src/backend/utils/cache/attoptcache.c
+++ b/src/backend/utils/cache/attoptcache.c
@@ -120,7 +120,7 @@ InitializeAttoptCache(void)
 	/* Watch for invalidation events. */
 	CacheRegisterSyscacheCallback(ATTNUM,
 								  InvalidateAttoptCacheCallback,
-								  (Datum) 0);
+								  DummyDatum);
 }
 
 /*
diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c
index e2cd3feaf81..097d3f48992 100644
--- a/src/backend/utils/cache/catcache.c
+++ b/src/backend/utils/cache/catcache.c
@@ -386,10 +386,10 @@ CatalogCacheComputeHashValue(CatCache *cache, int nkeys,
 static uint32
 CatalogCacheComputeTupleHashValue(CatCache *cache, int nkeys, HeapTuple tuple)
 {
-	Datum		v1 = 0,
-				v2 = 0,
-				v3 = 0,
-				v4 = 0;
+	Datum		v1 = DummyDatum,
+				v2 = DummyDatum,
+				v3 = DummyDatum,
+				v4 = DummyDatum;
 	bool		isNull = false;
 	int		   *cc_keyno = cache->cc_keyno;
 	TupleDesc	cc_tupdesc = cache->cc_tupdesc;
@@ -1358,7 +1358,7 @@ HeapTuple
 SearchCatCache1(CatCache *cache,
 				Datum v1)
 {
-	return SearchCatCacheInternal(cache, 1, v1, 0, 0, 0);
+	return SearchCatCacheInternal(cache, 1, v1, DummyDatum, DummyDatum, DummyDatum);
 }
 
 
@@ -1366,7 +1366,7 @@ HeapTuple
 SearchCatCache2(CatCache *cache,
 				Datum v1, Datum v2)
 {
-	return SearchCatCacheInternal(cache, 2, v1, v2, 0, 0);
+	return SearchCatCacheInternal(cache, 2, v1, v2, DummyDatum, DummyDatum);
 }
 
 
@@ -1374,7 +1374,7 @@ HeapTuple
 SearchCatCache3(CatCache *cache,
 				Datum v1, Datum v2, Datum v3)
 {
-	return SearchCatCacheInternal(cache, 3, v1, v2, v3, 0);
+	return SearchCatCacheInternal(cache, 3, v1, v2, v3, DummyDatum);
 }
 
 
@@ -1723,7 +1723,7 @@ SearchCatCacheList(CatCache *cache,
 				   Datum v2,
 				   Datum v3)
 {
-	Datum		v4 = 0;			/* dummy last-column value */
+	Datum		v4 = DummyDatum;			/* dummy last-column value */
 	Datum		arguments[CATCACHE_MAXKEYS];
 	uint32		lHashValue;
 	Index		lHashIndex;
diff --git a/src/backend/utils/cache/evtcache.c b/src/backend/utils/cache/evtcache.c
index ce596bf5638..e4f10158c71 100644
--- a/src/backend/utils/cache/evtcache.c
+++ b/src/backend/utils/cache/evtcache.c
@@ -107,7 +107,7 @@ BuildEventTriggerCache(void)
 								  ALLOCSET_DEFAULT_SIZES);
 		CacheRegisterSyscacheCallback(EVENTTRIGGEROID,
 									  InvalidateEventCacheCallback,
-									  (Datum) 0);
+									  DummyDatum);
 	}
 
 	/* Switch to correct memory context. */
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index 032bb6222c4..e85041e34b7 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -1078,7 +1078,7 @@ get_attoptions(Oid relid, int16 attnum)
 							  &isnull);
 
 	if (isnull)
-		result = (Datum) 0;
+		result = DummyDatum;
 	else
 		result = datumCopy(attopts, false, -1); /* text[] */
 
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index 0c506d320b1..05519bec9b6 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -145,14 +145,14 @@ int			plan_cache_mode = PLAN_CACHE_MODE_AUTO;
 void
 InitPlanCache(void)
 {
-	CacheRegisterRelcacheCallback(PlanCacheRelCallback, (Datum) 0);
-	CacheRegisterSyscacheCallback(PROCOID, PlanCacheObjectCallback, (Datum) 0);
-	CacheRegisterSyscacheCallback(TYPEOID, PlanCacheObjectCallback, (Datum) 0);
-	CacheRegisterSyscacheCallback(NAMESPACEOID, PlanCacheSysCallback, (Datum) 0);
-	CacheRegisterSyscacheCallback(OPEROID, PlanCacheSysCallback, (Datum) 0);
-	CacheRegisterSyscacheCallback(AMOPOPID, PlanCacheSysCallback, (Datum) 0);
-	CacheRegisterSyscacheCallback(FOREIGNSERVEROID, PlanCacheSysCallback, (Datum) 0);
-	CacheRegisterSyscacheCallback(FOREIGNDATAWRAPPEROID, PlanCacheSysCallback, (Datum) 0);
+	CacheRegisterRelcacheCallback(PlanCacheRelCallback, DummyDatum);
+	CacheRegisterSyscacheCallback(PROCOID, PlanCacheObjectCallback, DummyDatum);
+	CacheRegisterSyscacheCallback(TYPEOID, PlanCacheObjectCallback, DummyDatum);
+	CacheRegisterSyscacheCallback(NAMESPACEOID, PlanCacheSysCallback, DummyDatum);
+	CacheRegisterSyscacheCallback(OPEROID, PlanCacheSysCallback, DummyDatum);
+	CacheRegisterSyscacheCallback(AMOPOPID, PlanCacheSysCallback, DummyDatum);
+	CacheRegisterSyscacheCallback(FOREIGNSERVEROID, PlanCacheSysCallback, DummyDatum);
+	CacheRegisterSyscacheCallback(FOREIGNDATAWRAPPEROID, PlanCacheSysCallback, DummyDatum);
 }
 
 /*
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 6fe268a8eec..83a2d5c4747 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -5188,7 +5188,7 @@ RelationGetDummyIndexExpressions(Relation relation)
 								   exprTypmod(rawExpr),
 								   exprCollation(rawExpr),
 								   1,
-								   (Datum) 0,
+								   DummyDatum,
 								   true,
 								   true));
 	}
@@ -6009,7 +6009,7 @@ RelationGetIndexAttOptions(Relation relation, bool copy)
 
 			opts[i] = index_opclass_options(relation, i + 1, attoptions, false);
 
-			if (attoptions != (Datum) 0)
+			if (DatumGetPointer(attoptions) != NULL) // XXX idea pfree_if_nonnull
 				pfree(DatumGetPointer(attoptions));
 		}
 	}
diff --git a/src/backend/utils/cache/relfilenumbermap.c b/src/backend/utils/cache/relfilenumbermap.c
index 8a2f6f8c693..0ecf2b2afee 100644
--- a/src/backend/utils/cache/relfilenumbermap.c
+++ b/src/backend/utils/cache/relfilenumbermap.c
@@ -123,7 +123,7 @@ InitializeRelfilenumberMap(void)
 
 	/* Watch for invalidation events. */
 	CacheRegisterRelcacheCallback(RelfilenumberMapInvalidateCallback,
-								  (Datum) 0);
+								  DummyDatum);
 }
 
 /*
diff --git a/src/backend/utils/cache/spccache.c b/src/backend/utils/cache/spccache.c
index 23458599298..30d8a5881e7 100644
--- a/src/backend/utils/cache/spccache.c
+++ b/src/backend/utils/cache/spccache.c
@@ -93,7 +93,7 @@ InitializeTableSpaceCache(void)
 	/* Watch for invalidation events. */
 	CacheRegisterSyscacheCallback(TABLESPACEOID,
 								  InvalidateTableSpaceCacheCallback,
-								  (Datum) 0);
+								  DummyDatum);
 }
 
 /*
diff --git a/src/backend/utils/cache/typcache.c b/src/backend/utils/cache/typcache.c
index f9aec38a11f..ff674044d66 100644
--- a/src/backend/utils/cache/typcache.c
+++ b/src/backend/utils/cache/typcache.c
@@ -416,10 +416,10 @@ lookup_type_cache(Oid type_id, int flags)
 											 &ctl, HASH_ELEM | HASH_BLOBS);
 
 		/* Also set up callbacks for SI invalidations */
-		CacheRegisterRelcacheCallback(TypeCacheRelCallback, (Datum) 0);
-		CacheRegisterSyscacheCallback(TYPEOID, TypeCacheTypCallback, (Datum) 0);
-		CacheRegisterSyscacheCallback(CLAOID, TypeCacheOpcCallback, (Datum) 0);
-		CacheRegisterSyscacheCallback(CONSTROID, TypeCacheConstrCallback, (Datum) 0);
+		CacheRegisterRelcacheCallback(TypeCacheRelCallback, DummyDatum);
+		CacheRegisterSyscacheCallback(TYPEOID, TypeCacheTypCallback, DummyDatum);
+		CacheRegisterSyscacheCallback(CLAOID, TypeCacheOpcCallback, DummyDatum);
+		CacheRegisterSyscacheCallback(CONSTROID, TypeCacheConstrCallback, DummyDatum);
 
 		/* Also make sure CacheMemoryContext exists */
 		if (!CacheMemoryContext)
@@ -2283,7 +2283,7 @@ SharedRecordTypmodRegistryInit(SharedRecordTypmodRegistry *registry,
 	 * the memory, the leader process will use a shared registry until it
 	 * exits.
 	 */
-	on_dsm_detach(segment, shared_record_typmod_registry_detach, (Datum) 0);
+	on_dsm_detach(segment, shared_record_typmod_registry_detach, DummyDatum);
 }
 
 /*
diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c
index 782291d9998..37984d0f394 100644
--- a/src/backend/utils/fmgr/fmgr.c
+++ b/src/backend/utils/fmgr/fmgr.c
@@ -1533,7 +1533,7 @@ InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod)
 	Datum		result;
 
 	if (str == NULL && flinfo->fn_strict)
-		return (Datum) 0;		/* just return null result */
+		return DummyDatum;		/* just return null result */
 
 	InitFunctionCallInfoData(*fcinfo, flinfo, 3, InvalidOid, NULL, NULL);
 
@@ -1591,7 +1591,7 @@ InputFunctionCallSafe(FmgrInfo *flinfo, char *str,
 
 	if (str == NULL && flinfo->fn_strict)
 	{
-		*result = (Datum) 0;	/* just return null result */
+		*result = DummyDatum;	/* just return null result */
 		return true;
 	}
 
@@ -1646,7 +1646,7 @@ DirectInputFunctionCallSafe(PGFunction func, char *str,
 
 	if (str == NULL)
 	{
-		*result = (Datum) 0;	/* just return null result */
+		*result = DummyDatum;	/* just return null result */
 		return true;
 	}
 
@@ -1701,7 +1701,7 @@ ReceiveFunctionCall(FmgrInfo *flinfo, StringInfo buf,
 	Datum		result;
 
 	if (buf == NULL && flinfo->fn_strict)
-		return (Datum) 0;		/* just return null result */
+		return DummyDatum;		/* just return null result */
 
 	InitFunctionCallInfoData(*fcinfo, flinfo, 3, InvalidOid, NULL, NULL);
 
diff --git a/src/backend/utils/fmgr/funcapi.c b/src/backend/utils/fmgr/funcapi.c
index 5f2317211c9..5f38a52d648 100644
--- a/src/backend/utils/fmgr/funcapi.c
+++ b/src/backend/utils/fmgr/funcapi.c
@@ -1531,7 +1531,7 @@ get_func_input_arg_names(Datum proargnames, Datum proargmodes,
 	int			i;
 
 	/* Do nothing if null proargnames */
-	if (proargnames == PointerGetDatum(NULL))
+	if (DatumGetPointer(proargnames) == NULL)
 	{
 		*arg_names = NULL;
 		return 0;
@@ -1548,7 +1548,7 @@ get_func_input_arg_names(Datum proargnames, Datum proargmodes,
 		ARR_ELEMTYPE(arr) != TEXTOID)
 		elog(ERROR, "proargnames is not a 1-D text array or it contains nulls");
 	deconstruct_array_builtin(arr, TEXTOID, &argnames, NULL, &numargs);
-	if (proargmodes != PointerGetDatum(NULL))
+	if (DatumGetPointer(proargmodes) != NULL)
 	{
 		arr = DatumGetArrayTypeP(proargmodes);	/* ensure not toasted */
 		if (ARR_NDIM(arr) != 1 ||
@@ -1766,8 +1766,8 @@ build_function_result_tupdesc_d(char prokind,
 	int			i;
 
 	/* Can't have output args if columns are null */
-	if (proallargtypes == PointerGetDatum(NULL) ||
-		proargmodes == PointerGetDatum(NULL))
+	if (DatumGetPointer(proallargtypes) == NULL ||
+		DatumGetPointer(proargmodes) == NULL)
 		return NULL;
 
 	/*
@@ -1791,7 +1791,7 @@ build_function_result_tupdesc_d(char prokind,
 		elog(ERROR, "proargmodes is not a 1-D char array of length %d or it contains nulls",
 			 numargs);
 	argmodes = (char *) ARR_DATA_PTR(arr);
-	if (proargnames != PointerGetDatum(NULL))
+	if (DatumGetPointer(proargnames) != NULL)
 	{
 		arr = DatumGetArrayTypeP(proargnames);	/* ensure not toasted */
 		if (ARR_NDIM(arr) != 1 ||
@@ -2072,7 +2072,7 @@ extract_variadic_args(FunctionCallInfo fcinfo, int variadic_start,
 				types_res[i] = TEXTOID;
 
 				if (PG_ARGISNULL(i + variadic_start))
-					args_res[i] = (Datum) 0;
+					args_res[i] = DummyDatum;
 				else
 					args_res[i] =
 						CStringGetTextDatum(PG_GETARG_POINTER(i + variadic_start));
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index 43b4dbccc3d..47afb463920 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -1491,7 +1491,7 @@ CreateLockFile(const char *filename, bool amPostmaster,
 	 * to the list of files to unlink.
 	 */
 	if (lock_files == NIL)
-		on_proc_exit(UnlinkLockFiles, 0);
+		on_proc_exit(UnlinkLockFiles, DummyDatum);
 
 	/*
 	 * Use lcons so that the lock files are unlinked in reverse order of
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 641e535a73c..432508d1166 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -793,8 +793,8 @@ InitPostgres(const char *in_dbname, Oid dboid,
 		 * Use before_shmem_exit() so that ShutdownXLOG() can rely on DSM
 		 * segments etc to work (which in turn is required for pgstats).
 		 */
-		before_shmem_exit(pgstat_before_server_shutdown, 0);
-		before_shmem_exit(ShutdownXLOG, 0);
+		before_shmem_exit(pgstat_before_server_shutdown, DummyDatum);
+		before_shmem_exit(ShutdownXLOG, DummyDatum);
 	}
 
 	/*
@@ -825,7 +825,7 @@ InitPostgres(const char *in_dbname, Oid dboid,
 	 * initialization transaction, as is entirely possible, we need the
 	 * AbortTransaction call to clean up.
 	 */
-	before_shmem_exit(ShutdownPostgres, 0);
+	before_shmem_exit(ShutdownPostgres, DummyDatum);
 
 	/* The autovacuum launcher is done here */
 	if (AmAutoVacuumLauncherProcess())
diff --git a/src/backend/utils/misc/guc_funcs.c b/src/backend/utils/misc/guc_funcs.c
index b9e26982abd..22783e7dda3 100644
--- a/src/backend/utils/misc/guc_funcs.c
+++ b/src/backend/utils/misc/guc_funcs.c
@@ -1043,5 +1043,5 @@ show_all_file_settings(PG_FUNCTION_ARGS)
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
 
-	return (Datum) 0;
+	return DummyDatum;
 }
diff --git a/src/backend/utils/misc/pg_config.c b/src/backend/utils/misc/pg_config.c
index e64e6758c93..acef79d45e6 100644
--- a/src/backend/utils/misc/pg_config.c
+++ b/src/backend/utils/misc/pg_config.c
@@ -45,5 +45,5 @@ pg_config(PG_FUNCTION_ARGS)
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
 
-	return (Datum) 0;
+	return DummyDatum;
 }
diff --git a/src/backend/utils/misc/superuser.c b/src/backend/utils/misc/superuser.c
index 5858b0af64c..0887c08d892 100644
--- a/src/backend/utils/misc/superuser.c
+++ b/src/backend/utils/misc/superuser.c
@@ -84,7 +84,7 @@ superuser_arg(Oid roleid)
 	{
 		CacheRegisterSyscacheCallback(AUTHOID,
 									  RoleidCallback,
-									  (Datum) 0);
+									  DummyDatum);
 		roleid_callback_registered = true;
 	}
 
diff --git a/src/backend/utils/mmgr/portalmem.c b/src/backend/utils/mmgr/portalmem.c
index 0be1c2b0fff..51b314c2b88 100644
--- a/src/backend/utils/mmgr/portalmem.c
+++ b/src/backend/utils/mmgr/portalmem.c
@@ -1164,7 +1164,7 @@ pg_cursor(PG_FUNCTION_ARGS)
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
 
-	return (Datum) 0;
+	return DummyDatum;
 }
 
 bool
diff --git a/src/backend/utils/resowner/resowner.c b/src/backend/utils/resowner/resowner.c
index d39f3e1b655..68ceab4bc37 100644
--- a/src/backend/utils/resowner/resowner.c
+++ b/src/backend/utils/resowner/resowner.c
@@ -232,9 +232,9 @@ hash_resource_elem(Datum value, const ResourceOwnerDesc *kind)
 	 * result enough for our purposes.
 	 */
 #if SIZEOF_DATUM == 8
-	return hash_combine64(murmurhash64((uint64) value), (uint64) kind);
+	return hash_combine64(murmurhash64((uint64) value.value), (uint64) kind);
 #else
-	return hash_combine(murmurhash32((uint32) value), (uint32) kind);
+	return hash_combine(murmurhash32((uint32) value.value), (uint32) kind);
 #endif
 }
 
@@ -575,7 +575,7 @@ ResourceOwnerForget(ResourceOwner owner, Datum value, const ResourceOwnerDesc *k
 	/* Search through all items in the array first. */
 	for (int i = owner->narr - 1; i >= 0; i--)
 	{
-		if (owner->arr[i].item == value &&
+		if (owner->arr[i].item.value == value.value &&
 			owner->arr[i].kind == kind)
 		{
 			owner->arr[i] = owner->arr[owner->narr - 1];
@@ -597,10 +597,10 @@ ResourceOwnerForget(ResourceOwner owner, Datum value, const ResourceOwnerDesc *k
 		idx = hash_resource_elem(value, kind) & mask;
 		for (uint32 i = 0; i < owner->capacity; i++)
 		{
-			if (owner->hash[idx].item == value &&
+			if (owner->hash[idx].item.value == value.value &&
 				owner->hash[idx].kind == kind)
 			{
-				owner->hash[idx].item = (Datum) 0;
+				owner->hash[idx].item = DummyDatum;
 				owner->hash[idx].kind = NULL;
 				owner->nhash--;
 
@@ -851,7 +851,7 @@ ResourceOwnerReleaseAllOfKind(ResourceOwner owner, const ResourceOwnerDesc *kind
 		{
 			Datum		value = owner->hash[i].item;
 
-			owner->hash[i].item = (Datum) 0;
+			owner->hash[i].item = DummyDatum;
 			owner->hash[i].kind = NULL;
 			owner->nhash--;
 
@@ -1007,7 +1007,7 @@ CreateAuxProcessResourceOwner(void)
 	 * Register a shmem-exit callback for cleanup of aux-process resource
 	 * owner.  (This needs to run after, e.g., ShutdownXLOG.)
 	 */
-	on_shmem_exit(ReleaseAuxProcessResourcesCallback, 0);
+	on_shmem_exit(ReleaseAuxProcessResourcesCallback, DummyDatum);
 }
 
 /*
diff --git a/src/backend/utils/sort/tuplesort.c b/src/backend/utils/sort/tuplesort.c
index 65ab83fff8b..55373a1464b 100644
--- a/src/backend/utils/sort/tuplesort.c
+++ b/src/backend/utils/sort/tuplesort.c
@@ -3138,9 +3138,9 @@ free_sort_tuple(Tuplesortstate *state, SortTuple *stup)
 int
 ssup_datum_unsigned_cmp(Datum x, Datum y, SortSupport ssup)
 {
-	if (x < y)
+	if (x.value < y.value)
 		return -1;
-	else if (x > y)
+	else if (x.value > y.value)
 		return 1;
 	else
 		return 0;
diff --git a/src/backend/utils/sort/tuplesortvariants.c b/src/backend/utils/sort/tuplesortvariants.c
index c5d18e46716..2636a9d090e 100644
--- a/src/backend/utils/sort/tuplesortvariants.c
+++ b/src/backend/utils/sort/tuplesortvariants.c
@@ -896,7 +896,7 @@ tuplesort_putgintuple(Tuplesortstate *state, GinTuple *tuple, Size size)
 	memcpy(ctup, tuple, size);
 
 	stup.tuple = ctup;
-	stup.datum1 = (Datum) 0;
+	stup.datum1 = DummyDatum;
 	stup.isnull1 = false;
 
 	/* GetMemoryChunkSpace is not supported for bump contexts */
@@ -944,7 +944,7 @@ tuplesort_putdatum(Tuplesortstate *state, Datum val, bool isNull)
 		 * Set datum1 to zeroed representation for NULLs (to be consistent,
 		 * and to support cheap inequality tests for NULL abbreviated keys).
 		 */
-		stup.datum1 = !isNull ? val : (Datum) 0;
+		stup.datum1 = !isNull ? val : DummyDatum;
 		stup.isnull1 = isNull;
 		stup.tuple = NULL;		/* no separate storage */
 	}
@@ -1956,7 +1956,7 @@ readtup_index_gin(Tuplesortstate *state, SortTuple *stup,
 	stup->tuple = (void *) tuple;
 
 	/* no abbreviations (FIXME maybe use attrnum for this?) */
-	stup->datum1 = (Datum) 0;
+	stup->datum1 = DummyDatum;
 }
 
 /*
@@ -2046,7 +2046,7 @@ readtup_datum(Tuplesortstate *state, SortTuple *stup,
 	if (tuplen == 0)
 	{
 		/* it's NULL */
-		stup->datum1 = (Datum) 0;
+		stup->datum1 = DummyDatum;
 		stup->isnull1 = true;
 		stup->tuple = NULL;
 	}
diff --git a/src/include/access/gin.h b/src/include/access/gin.h
index 2e1076a0499..26744cb8507 100644
--- a/src/include/access/gin.h
+++ b/src/include/access/gin.h
@@ -81,13 +81,13 @@ StaticAssertDecl(sizeof(GinTernaryValue) == sizeof(bool),
 static inline GinTernaryValue
 DatumGetGinTernaryValue(Datum X)
 {
-	return (GinTernaryValue) X;
+	return (GinTernaryValue) X.value;
 }
 
 static inline Datum
 GinTernaryValueGetDatum(GinTernaryValue X)
 {
-	return (Datum) X;
+	return (Datum){.value = X};
 }
 
 #define PG_RETURN_GIN_TERNARY_VALUE(x) return GinTernaryValueGetDatum(x)
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index aa957cf3b01..62678703347 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -884,7 +884,7 @@ fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
 		if (att_isnull(attnum - 1, tup->t_data->t_bits))
 		{
 			*isnull = true;
-			return (Datum) NULL;
+			return DummyDatum;
 		}
 		else
 			return nocachegetattr(tup, attnum, tupleDesc);
diff --git a/src/include/access/itup.h b/src/include/access/itup.h
index 7066c2a2868..d976d9e0dbd 100644
--- a/src/include/access/itup.h
+++ b/src/include/access/itup.h
@@ -154,7 +154,7 @@ index_getattr(IndexTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
 		if (att_isnull(attnum - 1, (bits8 *) tup + sizeof(IndexTupleData)))
 		{
 			*isnull = true;
-			return (Datum) NULL;
+			return DummyDatum;
 		}
 		else
 			return nocache_index_getattr(tup, attnum, tupleDesc);
diff --git a/src/include/access/spgist_private.h b/src/include/access/spgist_private.h
index cb43a278f46..ade1b769b45 100644
--- a/src/include/access/spgist_private.h
+++ b/src/include/access/spgist_private.h
@@ -315,7 +315,7 @@ typedef SpGistInnerTupleData *SpGistInnerTuple;
 							 ((s)->attPrefixType.attbyval ? \
 							  *(Datum *) _SGITDATA(x) : \
 							  PointerGetDatum(_SGITDATA(x))) \
-							 : (Datum) 0)
+							 : DummyDatum)
 #define SGITNODEPTR(x)		((SpGistNodeTuple) (_SGITDATA(x) + (x)->prefixSize))
 
 /* Macro for iterating through the nodes of an inner tuple */
diff --git a/src/include/access/tupmacs.h b/src/include/access/tupmacs.h
index 6240ec930e7..10a57039630 100644
--- a/src/include/access/tupmacs.h
+++ b/src/include/access/tupmacs.h
@@ -68,7 +68,7 @@ fetch_att(const void *T, bool attbyval, int attlen)
 #endif
 			default:
 				elog(ERROR, "unsupported byval length: %d", attlen);
-				return 0;
+				return DummyDatum;
 		}
 	}
 	else
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 104b059544d..c529b29c521 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -416,7 +416,7 @@ ExecEvalExprNoReturn(ExprState *state,
 
 	retDatum = state->evalfunc(state, econtext, NULL);
 
-	Assert(retDatum == (Datum) 0);
+	Assert(retDatum.value == 0);  // XXX
 }
 #endif
 
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index 0fe7b4ebc77..a0a2816f1c7 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -343,10 +343,12 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 
 /* To return a NULL do this: */
 #define PG_RETURN_NULL()  \
-	do { fcinfo->isnull = true; return (Datum) 0; } while (0)
+	do { fcinfo->isnull = true; return DummyDatum; } while (0)
+
+#define PG_RETURN_DUMMY()	 return DummyDatum
 
 /* A few internal functions return void (which is not the same as NULL!) */
-#define PG_RETURN_VOID()	 return (Datum) 0
+#define PG_RETURN_VOID()	 PG_RETURN_DUMMY()
 
 /* Macros for returning results of standard types */
 
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index fbe333d88fa..a4c1cfddea4 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -188,6 +188,8 @@ castNodeImpl(NodeTag type, void *ptr)
  * ----------------------------------------------------------------
  */
 
+typedef struct Datum Datum;
+
 /*
  * nodes/{outfuncs.c,print.c}
  */
@@ -198,7 +200,7 @@ extern void outNode(struct StringInfoData *str, const void *obj);
 extern void outToken(struct StringInfoData *str, const char *s);
 extern void outBitmapset(struct StringInfoData *str,
 						 const struct Bitmapset *bms);
-extern void outDatum(struct StringInfoData *str, uintptr_t value,
+extern void outDatum(struct StringInfoData *str, Datum value,
 					 int typlen, bool typbyval);
 extern char *nodeToString(const void *obj);
 extern char *nodeToStringWithLocations(const void *obj);
@@ -212,7 +214,7 @@ extern void *stringToNode(const char *str);
 extern void *stringToNodeWithLocations(const char *str);
 #endif
 extern struct Bitmapset *readBitmapset(void);
-extern uintptr_t readDatum(bool typbyval);
+extern Datum readDatum(bool typbyval);
 extern bool *readBoolCols(int numCols);
 extern int *readIntCols(int numCols);
 extern Oid *readOidCols(int numCols);
diff --git a/src/include/port/pg_bswap.h b/src/include/port/pg_bswap.h
index 33648433c63..762d9b4c02f 100644
--- a/src/include/port/pg_bswap.h
+++ b/src/include/port/pg_bswap.h
@@ -148,12 +148,12 @@ pg_bswap64(uint64 x)
  */
 #ifdef SIZEOF_DATUM
 #ifdef WORDS_BIGENDIAN
-#define		DatumBigEndianToNative(x)	(x)
+#define		DatumBigEndianToNative(x)	(x.value)
 #else							/* !WORDS_BIGENDIAN */
 #if SIZEOF_DATUM == 8
-#define		DatumBigEndianToNative(x)	pg_bswap64(x)
+#define		DatumBigEndianToNative(x)	pg_bswap64(x.value)
 #else							/* SIZEOF_DATUM != 8 */
-#define		DatumBigEndianToNative(x)	pg_bswap32(x)
+#define		DatumBigEndianToNative(x)	pg_bswap32(x.value)
 #endif							/* SIZEOF_DATUM == 8 */
 #endif							/* WORDS_BIGENDIAN */
 #endif							/* SIZEOF_DATUM */
diff --git a/src/include/postgres.h b/src/include/postgres.h
index 8a41a668687..4c51a78ae9b 100644
--- a/src/include/postgres.h
+++ b/src/include/postgres.h
@@ -65,8 +65,11 @@
  * The functions below and the analogous functions for other types should be used to
  * convert between a Datum and the appropriate C type.
  */
+typedef struct Datum {
+	uintptr_t value;
+} Datum;
 
-typedef uintptr_t Datum;
+#define DummyDatum ((Datum){0})
 
 /*
  * A NullableDatum is used in places where both a Datum and its nullness needs
@@ -94,7 +97,7 @@ typedef struct NullableDatum
 static inline bool
 DatumGetBool(Datum X)
 {
-	return (X != 0);
+	return (X.value != 0);
 }
 
 /*
@@ -106,7 +109,7 @@ DatumGetBool(Datum X)
 static inline Datum
 BoolGetDatum(bool X)
 {
-	return (Datum) (X ? 1 : 0);
+	return (Datum){.value = X ? 1 : 0};
 }
 
 /*
@@ -116,7 +119,7 @@ BoolGetDatum(bool X)
 static inline char
 DatumGetChar(Datum X)
 {
-	return (char) X;
+	return (char) X.value;
 }
 
 /*
@@ -126,7 +129,7 @@ DatumGetChar(Datum X)
 static inline Datum
 CharGetDatum(char X)
 {
-	return (Datum) X;
+	return (Datum){.value = X};
 }
 
 /*
@@ -136,7 +139,7 @@ CharGetDatum(char X)
 static inline Datum
 Int8GetDatum(int8 X)
 {
-	return (Datum) X;
+	return (Datum){.value = X};
 }
 
 /*
@@ -146,7 +149,7 @@ Int8GetDatum(int8 X)
 static inline uint8
 DatumGetUInt8(Datum X)
 {
-	return (uint8) X;
+	return (uint8) X.value;
 }
 
 /*
@@ -156,7 +159,7 @@ DatumGetUInt8(Datum X)
 static inline Datum
 UInt8GetDatum(uint8 X)
 {
-	return (Datum) X;
+	return (Datum){.value = X};
 }
 
 /*
@@ -166,7 +169,7 @@ UInt8GetDatum(uint8 X)
 static inline int16
 DatumGetInt16(Datum X)
 {
-	return (int16) X;
+	return (int16) X.value;
 }
 
 /*
@@ -176,7 +179,7 @@ DatumGetInt16(Datum X)
 static inline Datum
 Int16GetDatum(int16 X)
 {
-	return (Datum) X;
+	return (Datum){.value = X};
 }
 
 /*
@@ -186,7 +189,7 @@ Int16GetDatum(int16 X)
 static inline uint16
 DatumGetUInt16(Datum X)
 {
-	return (uint16) X;
+	return (uint16) X.value;
 }
 
 /*
@@ -196,7 +199,7 @@ DatumGetUInt16(Datum X)
 static inline Datum
 UInt16GetDatum(uint16 X)
 {
-	return (Datum) X;
+	return (Datum){.value = X};
 }
 
 /*
@@ -206,7 +209,7 @@ UInt16GetDatum(uint16 X)
 static inline int32
 DatumGetInt32(Datum X)
 {
-	return (int32) X;
+	return (int32) X.value;
 }
 
 /*
@@ -216,7 +219,7 @@ DatumGetInt32(Datum X)
 static inline Datum
 Int32GetDatum(int32 X)
 {
-	return (Datum) X;
+	return (Datum){.value = X};
 }
 
 /*
@@ -226,7 +229,7 @@ Int32GetDatum(int32 X)
 static inline uint32
 DatumGetUInt32(Datum X)
 {
-	return (uint32) X;
+	return (uint32) X.value;
 }
 
 /*
@@ -236,7 +239,7 @@ DatumGetUInt32(Datum X)
 static inline Datum
 UInt32GetDatum(uint32 X)
 {
-	return (Datum) X;
+	return (Datum){.value = X};
 }
 
 /*
@@ -246,7 +249,7 @@ UInt32GetDatum(uint32 X)
 static inline Oid
 DatumGetObjectId(Datum X)
 {
-	return (Oid) X;
+	return (Oid) X.value;
 }
 
 /*
@@ -256,7 +259,7 @@ DatumGetObjectId(Datum X)
 static inline Datum
 ObjectIdGetDatum(Oid X)
 {
-	return (Datum) X;
+	return (Datum){.value = X};
 }
 
 /*
@@ -266,7 +269,7 @@ ObjectIdGetDatum(Oid X)
 static inline TransactionId
 DatumGetTransactionId(Datum X)
 {
-	return (TransactionId) X;
+	return (TransactionId) X.value;
 }
 
 /*
@@ -276,7 +279,7 @@ DatumGetTransactionId(Datum X)
 static inline Datum
 TransactionIdGetDatum(TransactionId X)
 {
-	return (Datum) X;
+	return (Datum){.value = X};
 }
 
 /*
@@ -286,7 +289,7 @@ TransactionIdGetDatum(TransactionId X)
 static inline Datum
 MultiXactIdGetDatum(MultiXactId X)
 {
-	return (Datum) X;
+	return (Datum){.value = X};
 }
 
 /*
@@ -296,7 +299,7 @@ MultiXactIdGetDatum(MultiXactId X)
 static inline CommandId
 DatumGetCommandId(Datum X)
 {
-	return (CommandId) X;
+	return (CommandId) X.value;
 }
 
 /*
@@ -306,7 +309,7 @@ DatumGetCommandId(Datum X)
 static inline Datum
 CommandIdGetDatum(CommandId X)
 {
-	return (Datum) X;
+	return (Datum){.value = X};
 }
 
 /*
@@ -316,7 +319,7 @@ CommandIdGetDatum(CommandId X)
 static inline Pointer
 DatumGetPointer(Datum X)
 {
-	return (Pointer) X;
+	return (Pointer) X.value;
 }
 
 /*
@@ -326,7 +329,7 @@ DatumGetPointer(Datum X)
 static inline Datum
 PointerGetDatum(const void *X)
 {
-	return (Datum) X;
+	return (Datum){.value = (uintptr_t) X};
 }
 
 /*
@@ -390,7 +393,7 @@ static inline int64
 DatumGetInt64(Datum X)
 {
 #ifdef USE_FLOAT8_BYVAL
-	return (int64) X;
+	return (int64) X.value;
 #else
 	return *((int64 *) DatumGetPointer(X));
 #endif
@@ -407,7 +410,7 @@ DatumGetInt64(Datum X)
 static inline Datum
 Int64GetDatum(int64 X)
 {
-	return (Datum) X;
+	return (Datum){.value = X};
 }
 #else
 extern Datum Int64GetDatum(int64 X);
@@ -424,7 +427,7 @@ static inline uint64
 DatumGetUInt64(Datum X)
 {
 #ifdef USE_FLOAT8_BYVAL
-	return (uint64) X;
+	return (uint64) X.value;
 #else
 	return *((uint64 *) DatumGetPointer(X));
 #endif
@@ -441,7 +444,7 @@ static inline Datum
 UInt64GetDatum(uint64 X)
 {
 #ifdef USE_FLOAT8_BYVAL
-	return (Datum) X;
+	return (Datum){.value = X};
 #else
 	return Int64GetDatum((int64) X);
 #endif
diff --git a/src/include/utils/arrayaccess.h b/src/include/utils/arrayaccess.h
index 0e48ee07f57..d43837931ed 100644
--- a/src/include/utils/arrayaccess.h
+++ b/src/include/utils/arrayaccess.h
@@ -93,7 +93,7 @@ array_iter_next(array_iter *it, bool *isnull, int i,
 		if (it->bitmapptr && (*(it->bitmapptr) & it->bitmask) == 0)
 		{
 			*isnull = true;
-			ret = (Datum) 0;
+			ret = DummyDatum;
 		}
 		else
 		{
diff --git a/src/include/utils/sortsupport.h b/src/include/utils/sortsupport.h
index b7abaf7802d..699c7c5d675 100644
--- a/src/include/utils/sortsupport.h
+++ b/src/include/utils/sortsupport.h
@@ -254,7 +254,7 @@ ApplyUnsignedSortComparator(Datum datum1, bool isNull1,
 	}
 	else
 	{
-		compare = datum1 < datum2 ? -1 : datum1 > datum2 ? 1 : 0;
+		compare = datum1.value < datum2.value ? -1 : datum1.value > datum2.value ? 1 : 0;
 		if (ssup->ssup_reverse)
 			INVERT_COMPARE_RESULT(compare);
 	}
diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h
index 3039713259e..4b9633a2e7a 100644
--- a/src/include/utils/syscache.h
+++ b/src/include/utils/syscache.h
@@ -89,45 +89,45 @@ extern bool RelationSupportsSysCache(Oid relid);
  * maximum number of keys.
  */
 #define SearchSysCacheCopy1(cacheId, key1) \
-	SearchSysCacheCopy(cacheId, key1, 0, 0, 0)
+	SearchSysCacheCopy(cacheId, key1, DummyDatum, DummyDatum, DummyDatum)
 #define SearchSysCacheCopy2(cacheId, key1, key2) \
-	SearchSysCacheCopy(cacheId, key1, key2, 0, 0)
+	SearchSysCacheCopy(cacheId, key1, key2, DummyDatum, DummyDatum)
 #define SearchSysCacheCopy3(cacheId, key1, key2, key3) \
-	SearchSysCacheCopy(cacheId, key1, key2, key3, 0)
+	SearchSysCacheCopy(cacheId, key1, key2, key3, DummyDatum)
 #define SearchSysCacheCopy4(cacheId, key1, key2, key3, key4) \
 	SearchSysCacheCopy(cacheId, key1, key2, key3, key4)
 
 #define SearchSysCacheExists1(cacheId, key1) \
-	SearchSysCacheExists(cacheId, key1, 0, 0, 0)
+	SearchSysCacheExists(cacheId, key1, DummyDatum, DummyDatum, DummyDatum)
 #define SearchSysCacheExists2(cacheId, key1, key2) \
-	SearchSysCacheExists(cacheId, key1, key2, 0, 0)
+	SearchSysCacheExists(cacheId, key1, key2, DummyDatum, DummyDatum)
 #define SearchSysCacheExists3(cacheId, key1, key2, key3) \
-	SearchSysCacheExists(cacheId, key1, key2, key3, 0)
+	SearchSysCacheExists(cacheId, key1, key2, key3, DummyDatum)
 #define SearchSysCacheExists4(cacheId, key1, key2, key3, key4) \
 	SearchSysCacheExists(cacheId, key1, key2, key3, key4)
 
 #define GetSysCacheOid1(cacheId, oidcol, key1) \
-	GetSysCacheOid(cacheId, oidcol, key1, 0, 0, 0)
+	GetSysCacheOid(cacheId, oidcol, key1, DummyDatum, DummyDatum, DummyDatum)
 #define GetSysCacheOid2(cacheId, oidcol, key1, key2) \
-	GetSysCacheOid(cacheId, oidcol, key1, key2, 0, 0)
+	GetSysCacheOid(cacheId, oidcol, key1, key2, DummyDatum, DummyDatum)
 #define GetSysCacheOid3(cacheId, oidcol, key1, key2, key3) \
-	GetSysCacheOid(cacheId, oidcol, key1, key2, key3, 0)
+	GetSysCacheOid(cacheId, oidcol, key1, key2, key3, DummyDatum)
 #define GetSysCacheOid4(cacheId, oidcol, key1, key2, key3, key4) \
 	GetSysCacheOid(cacheId, oidcol, key1, key2, key3, key4)
 
 #define GetSysCacheHashValue1(cacheId, key1) \
-	GetSysCacheHashValue(cacheId, key1, 0, 0, 0)
+	GetSysCacheHashValue(cacheId, key1, DummyDatum, DummyDatum, DummyDatum)
 #define GetSysCacheHashValue2(cacheId, key1, key2) \
-	GetSysCacheHashValue(cacheId, key1, key2, 0, 0)
+	GetSysCacheHashValue(cacheId, key1, key2, DummyDatum, DummyDatum)
 #define GetSysCacheHashValue3(cacheId, key1, key2, key3) \
-	GetSysCacheHashValue(cacheId, key1, key2, key3, 0)
+	GetSysCacheHashValue(cacheId, key1, key2, key3, DummyDatum)
 #define GetSysCacheHashValue4(cacheId, key1, key2, key3, key4) \
 	GetSysCacheHashValue(cacheId, key1, key2, key3, key4)
 
 #define SearchSysCacheList1(cacheId, key1) \
-	SearchSysCacheList(cacheId, 1, key1, 0, 0)
+	SearchSysCacheList(cacheId, 1, key1, DummyDatum, DummyDatum)
 #define SearchSysCacheList2(cacheId, key1, key2) \
-	SearchSysCacheList(cacheId, 2, key1, key2, 0)
+	SearchSysCacheList(cacheId, 2, key1, key2, DummyDatum)
 #define SearchSysCacheList3(cacheId, key1, key2, key3) \
 	SearchSysCacheList(cacheId, 3, key1, key2, key3)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 73ba1748fe0..e46bda3c108 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -617,7 +617,7 @@ select_perl_context(bool trusted)
 			plperl_untrusted_init();
 
 		/* successfully initialized, so arrange for cleanup */
-		on_proc_exit(plperl_fini, 0);
+		on_proc_exit(plperl_fini, DummyDatum);
 	}
 	else
 	{
@@ -1853,7 +1853,7 @@ PG_FUNCTION_INFO_V1(plperl_call_handler);
 Datum
 plperl_call_handler(PG_FUNCTION_ARGS)
 {
-	Datum		retval = (Datum) 0;
+	Datum		retval = DummyDatum;
 	plperl_call_data *volatile save_call_data = current_call_data;
 	plperl_interp_desc *volatile oldinterp = plperl_active_interp;
 	plperl_call_data this_call_data;
@@ -1870,7 +1870,7 @@ plperl_call_handler(PG_FUNCTION_ARGS)
 		else if (CALLED_AS_EVENT_TRIGGER(fcinfo))
 		{
 			plperl_event_trigger_handler(fcinfo);
-			retval = (Datum) 0;
+			retval = DummyDatum;
 		}
 		else
 			retval = plperl_func_handler(fcinfo);
@@ -2405,7 +2405,7 @@ plperl_func_handler(PG_FUNCTION_ARGS)
 	bool		nonatomic;
 	plperl_proc_desc *prodesc;
 	SV		   *perlret;
-	Datum		retval = 0;
+	Datum		retval = DummyDatum;
 	ReturnSetInfo *rsi;
 	ErrorContextCallback pl_error_context;
 
@@ -2492,7 +2492,7 @@ plperl_func_handler(PG_FUNCTION_ARGS)
 			rsi->setResult = current_call_data->tuple_store;
 			rsi->setDesc = current_call_data->ret_tdesc;
 		}
-		retval = (Datum) 0;
+		retval = DummyDatum;
 	}
 	else if (prodesc->result_oid)
 	{
@@ -2577,7 +2577,7 @@ plperl_trigger_handler(PG_FUNCTION_ARGS)
 		else if (TRIGGER_FIRED_BY_TRUNCATE(trigdata->tg_event))
 			retval = PointerGetDatum(trigdata->tg_trigtuple);
 		else
-			retval = (Datum) 0; /* can this happen? */
+			retval = DummyDatum; /* can this happen? */
 	}
 	else
 	{
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index ee961425a5b..795072114b1 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -1770,7 +1770,7 @@ plpgsql_build_variable(const char *refname, int lineno, PLpgSQL_type *dtype,
 				/* other fields are left as 0, might be changed by caller */
 
 				/* preset to NULL */
-				var->value = 0;
+				var->value = DummyDatum;
 				var->isnull = true;
 				var->freeval = false;
 
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index d19425b7a71..39095da2cd0 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -675,7 +675,7 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo,
 			rsi->setDesc = CreateTupleDescCopy(estate.tuple_store_desc);
 			MemoryContextSwitchTo(oldcxt);
 		}
-		estate.retval = (Datum) 0;
+		estate.retval = DummyDatum;
 		fcinfo->isnull = true;
 	}
 	else if (!estate.retisnull)
@@ -1016,7 +1016,7 @@ plpgsql_exec_trigger(PLpgSQL_function *func,
 				if (TupleDescAttr(tupdesc, i)->attgenerated == ATTRIBUTE_GENERATED_STORED)
 					expanded_record_set_field_internal(rec_new->erh,
 													   i + 1,
-													   (Datum) 0,
+													   DummyDatum,
 													   true,	/* isnull */
 													   false, false);
 		}
@@ -1512,7 +1512,7 @@ plpgsql_fulfill_promise(PLpgSQL_execstate *estate,
 			}
 			else
 			{
-				assign_simple_var(estate, var, (Datum) 0, true, false);
+				assign_simple_var(estate, var, DummyDatum, true, false);
 			}
 			break;
 
@@ -1697,7 +1697,7 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
 					 * Free any old value, in case re-entering block, and
 					 * initialize to NULL
 					 */
-					assign_simple_var(estate, var, (Datum) 0, true, false);
+					assign_simple_var(estate, var, DummyDatum, true, false);
 
 					if (var->default_val == NULL)
 					{
@@ -1710,7 +1710,7 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
 						if (var->datatype->typtype == TYPTYPE_DOMAIN)
 							exec_assign_value(estate,
 											  (PLpgSQL_datum *) var,
-											  (Datum) 0,
+											  DummyDatum,
 											  true,
 											  UNKNOWNOID,
 											  -1);
@@ -2611,7 +2611,7 @@ exec_stmt_case(PLpgSQL_execstate *estate, PLpgSQL_stmt_case *stmt)
 
 			/* We can now discard any value we had for the temp variable */
 			if (t_var != NULL)
-				assign_simple_var(estate, t_var, (Datum) 0, true, false);
+				assign_simple_var(estate, t_var, DummyDatum, true, false);
 
 			/* Evaluate the statement(s), and we're done */
 			return exec_stmts(estate, cwt->stmts);
@@ -2620,7 +2620,7 @@ exec_stmt_case(PLpgSQL_execstate *estate, PLpgSQL_stmt_case *stmt)
 
 	/* We can now discard any value we had for the temp variable */
 	if (t_var != NULL)
-		assign_simple_var(estate, t_var, (Datum) 0, true, false);
+		assign_simple_var(estate, t_var, DummyDatum, true, false);
 
 	/* SQL2003 mandates this error if there was no ELSE clause */
 	if (!stmt->have_else)
@@ -2990,7 +2990,7 @@ exec_stmt_forc(PLpgSQL_execstate *estate, PLpgSQL_stmt_forc *stmt)
 	SPI_cursor_close(portal);
 
 	if (curname == NULL)
-		assign_simple_var(estate, curvar, (Datum) 0, true, false);
+		assign_simple_var(estate, curvar, DummyDatum, true, false);
 
 	return rc;
 }
@@ -3205,7 +3205,7 @@ exec_stmt_return(PLpgSQL_execstate *estate, PLpgSQL_stmt_return *stmt)
 		return PLPGSQL_RC_RETURN;
 
 	/* initialize for null result */
-	estate->retval = (Datum) 0;
+	estate->retval = DummyDatum;
 	estate->retisnull = true;
 	estate->rettype = InvalidOid;
 
@@ -3322,7 +3322,7 @@ exec_stmt_return(PLpgSQL_execstate *estate, PLpgSQL_stmt_return *stmt)
 	if (estate->fn_rettype == VOIDOID &&
 		estate->func->fn_prokind != PROKIND_PROCEDURE)
 	{
-		estate->retval = (Datum) 0;
+		estate->retval = DummyDatum;
 		estate->retisnull = false;
 		estate->rettype = VOIDOID;
 	}
@@ -4005,7 +4005,7 @@ plpgsql_estate_setup(PLpgSQL_execstate *estate,
 	estate->trigdata = NULL;
 	estate->evtrigdata = NULL;
 
-	estate->retval = (Datum) 0;
+	estate->retval = DummyDatum;
 	estate->retisnull = true;
 	estate->rettype = InvalidOid;
 
@@ -5148,7 +5148,7 @@ exec_assign_value(PLpgSQL_execstate *estate,
 				 * promise in any case --- otherwise, assigning null to an
 				 * armed promise variable would fail to disarm the promise.
 				 */
-				if (var->value != newvalue || var->isnull || isNull)
+				if (var->value.value != newvalue.value || var->isnull || isNull)
 					assign_simple_var(estate, var, newvalue, isNull,
 									  (!var->datatype->typbyval && !isNull));
 				else
@@ -5356,7 +5356,7 @@ exec_eval_datum(PLpgSQL_execstate *estate,
 				if (rec->erh == NULL)
 				{
 					/* Treat uninstantiated record as a simple NULL */
-					*value = (Datum) 0;
+					*value = DummyDatum;
 					*isnull = true;
 					/* Report variable's declared type */
 					*typeid = rec->rectypeid;
@@ -5367,7 +5367,7 @@ exec_eval_datum(PLpgSQL_execstate *estate,
 					if (ExpandedRecordIsEmpty(rec->erh))
 					{
 						/* Empty record is also a NULL */
-						*value = (Datum) 0;
+						*value = DummyDatum;
 						*isnull = true;
 					}
 					else
@@ -5682,7 +5682,7 @@ exec_eval_expr(PLpgSQL_execstate *estate,
 			   Oid *rettype,
 			   int32 *rettypmod)
 {
-	Datum		result = 0;
+	Datum		result = DummyDatum;
 	int			rc;
 	Form_pg_attribute attr;
 
@@ -5735,7 +5735,7 @@ exec_eval_expr(PLpgSQL_execstate *estate,
 	if (estate->eval_processed == 0)
 	{
 		*isNull = true;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 
 	/*
@@ -6401,7 +6401,7 @@ plpgsql_param_fetch(ParamListInfo params,
 	/* Return "no such parameter" if not ok */
 	if (!ok)
 	{
-		prm->value = (Datum) 0;
+		prm->value = DummyDatum;
 		prm->isnull = true;
 		prm->pflags = 0;
 		prm->ptype = InvalidOid;
@@ -6658,7 +6658,7 @@ plpgsql_param_eval_var_transfer(ExprState *state, ExprEvalStep *op,
 											   get_eval_mcontext(estate));
 		*op->resnull = false;
 
-		var->value = (Datum) 0;
+		var->value = DummyDatum;
 		var->isnull = true;
 		var->freeval = false;
 	}
@@ -7293,7 +7293,7 @@ exec_move_row_from_fields(PLpgSQL_execstate *estate,
 				else
 				{
 					/* no source for destination column */
-					value = (Datum) 0;
+					value = DummyDatum;
 					isnull = true;
 					valtype = UNKNOWNOID;
 					valtypmod = -1;
@@ -7402,7 +7402,7 @@ exec_move_row_from_fields(PLpgSQL_execstate *estate,
 			else
 			{
 				/* no source for destination column */
-				value = (Datum) 0;
+				value = DummyDatum;
 				isnull = true;
 				valtype = UNKNOWNOID;
 				valtypmod = -1;
diff --git a/src/pl/plpgsql/src/pl_handler.c b/src/pl/plpgsql/src/pl_handler.c
index e9a72929947..479819d1aa2 100644
--- a/src/pl/plpgsql/src/pl_handler.c
+++ b/src/pl/plpgsql/src/pl_handler.c
@@ -227,7 +227,7 @@ plpgsql_call_handler(PG_FUNCTION_ARGS)
 	PLpgSQL_function *func;
 	PLpgSQL_execstate *save_cur_estate;
 	ResourceOwner procedure_resowner;
-	volatile Datum retval = (Datum) 0;
+	volatile Datum retval = DummyDatum;
 	int			rc;
 
 	nonatomic = fcinfo->context &&
diff --git a/src/pl/plpython/plpy_exec.c b/src/pl/plpython/plpy_exec.c
index 28fbd443b98..ee130bf0351 100644
--- a/src/pl/plpython/plpy_exec.c
+++ b/src/pl/plpython/plpy_exec.c
@@ -214,7 +214,7 @@ PLy_exec_function(FunctionCallInfo fcinfo, PLyProcedure *proc)
 			}
 
 			fcinfo->isnull = false;
-			rv = (Datum) 0;
+			rv = DummyDatum;
 		}
 		else if (plrv == Py_None &&
 				 srfstate && srfstate->iter == NULL)
@@ -225,7 +225,7 @@ PLy_exec_function(FunctionCallInfo fcinfo, PLyProcedure *proc)
 			 * complain.
 			 */
 			fcinfo->isnull = true;
-			rv = (Datum) 0;
+			rv = DummyDatum;
 		}
 		else
 		{
diff --git a/src/pl/plpython/plpy_typeio.c b/src/pl/plpython/plpy_typeio.c
index f6509a41902..69f3c9ab413 100644
--- a/src/pl/plpython/plpy_typeio.c
+++ b/src/pl/plpython/plpy_typeio.c
@@ -885,7 +885,7 @@ PLyObject_ToBool(PLyObToDatum *arg, PyObject *plrv,
 	if (plrv == Py_None)
 	{
 		*isnull = true;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 	*isnull = false;
 	return BoolGetDatum(PyObject_IsTrue(plrv));
@@ -901,12 +901,12 @@ PLyObject_ToBytea(PLyObToDatum *arg, PyObject *plrv,
 				  bool *isnull, bool inarray)
 {
 	PyObject   *volatile plrv_so = NULL;
-	Datum		rv = (Datum) 0;
+	Datum		rv = DummyDatum;
 
 	if (plrv == Py_None)
 	{
 		*isnull = true;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 	*isnull = false;
 
@@ -950,7 +950,7 @@ PLyObject_ToComposite(PLyObToDatum *arg, PyObject *plrv,
 	if (plrv == Py_None)
 	{
 		*isnull = true;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 	*isnull = false;
 
@@ -1082,7 +1082,7 @@ PLyObject_ToScalar(PLyObToDatum *arg, PyObject *plrv,
 	if (plrv == Py_None)
 	{
 		*isnull = true;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 	*isnull = false;
 
@@ -1122,7 +1122,7 @@ PLyObject_ToTransform(PLyObToDatum *arg, PyObject *plrv,
 	if (plrv == Py_None)
 	{
 		*isnull = true;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 	*isnull = false;
 	return FunctionCall1(&arg->u.transform.typtransform, PointerGetDatum(plrv));
@@ -1144,7 +1144,7 @@ PLySequence_ToArray(PLyObToDatum *arg, PyObject *plrv,
 	if (plrv == Py_None)
 	{
 		*isnull = true;
-		return (Datum) 0;
+		return DummyDatum;
 	}
 	*isnull = false;
 
@@ -1364,7 +1364,7 @@ PLyMapping_ToComposite(PLyObToDatum *arg, TupleDesc desc, PyObject *mapping)
 
 		if (attr->attisdropped)
 		{
-			values[i] = (Datum) 0;
+			//values[i] = DummyDatum;
 			nulls[i] = true;
 			continue;
 		}
@@ -1445,7 +1445,7 @@ PLySequence_ToComposite(PLyObToDatum *arg, TupleDesc desc, PyObject *sequence)
 
 		if (TupleDescAttr(desc, i)->attisdropped)
 		{
-			values[i] = (Datum) 0;
+			//values[i] = DummyDatum;
 			nulls[i] = true;
 			continue;
 		}
@@ -1504,7 +1504,7 @@ PLyGenericObject_ToComposite(PLyObToDatum *arg, TupleDesc desc, PyObject *object
 
 		if (attr->attisdropped)
 		{
-			values[i] = (Datum) 0;
+			//values[i] = DummyDatum;
 			nulls[i] = true;
 			continue;
 		}
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index 73d660e88a6..de3d4f6a5ab 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -726,7 +726,7 @@ pltclu_call_handler(PG_FUNCTION_ARGS)
 static Datum
 pltcl_handler(PG_FUNCTION_ARGS, bool pltrusted)
 {
-	Datum		retval = (Datum) 0;
+	Datum		retval = DummyDatum;
 	pltcl_call_state current_call_state;
 	pltcl_call_state *save_call_state;
 
@@ -764,7 +764,7 @@ pltcl_handler(PG_FUNCTION_ARGS, bool pltrusted)
 		{
 			/* invoke the event trigger handler */
 			pltcl_event_trigger_handler(fcinfo, &current_call_state, pltrusted);
-			retval = (Datum) 0;
+			retval = DummyDatum;
 		}
 		else
 		{
@@ -978,7 +978,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 				MemoryContextSwitchTo(oldcxt);
 			}
 		}
-		retval = (Datum) 0;
+		retval = DummyDatum;
 		fcinfo->isnull = true;
 	}
 	else if (fcinfo->isnull)
diff --git a/src/test/modules/injection_points/injection_points.c b/src/test/modules/injection_points/injection_points.c
index 31138301117..f07bd27c7f5 100644
--- a/src/test/modules/injection_points/injection_points.c
+++ b/src/test/modules/injection_points/injection_points.c
@@ -512,7 +512,7 @@ injection_points_set_local(PG_FUNCTION_ARGS)
 	 * Register a before_shmem_exit callback to remove any injection points
 	 * linked to this process.
 	 */
-	before_shmem_exit(injection_points_cleanup, (Datum) 0);
+	before_shmem_exit(injection_points_cleanup, DummyDatum);
 
 	PG_RETURN_VOID();
 }
@@ -580,7 +580,7 @@ injection_points_list(PG_FUNCTION_ARGS)
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
 
-	return (Datum) 0;
+	return DummyDatum;
 #undef NUM_INJECTION_POINTS_LIST
 }
 
diff --git a/src/test/modules/injection_points/injection_stats.c b/src/test/modules/injection_points/injection_stats.c
index e3947b23ba5..072aa70ae53 100644
--- a/src/test/modules/injection_points/injection_stats.c
+++ b/src/test/modules/injection_points/injection_stats.c
@@ -212,7 +212,7 @@ PG_FUNCTION_INFO_V1(injection_points_stats_drop);
 Datum
 injection_points_stats_drop(PG_FUNCTION_ARGS)
 {
-	pgstat_drop_matching_entries(match_inj_entries, 0);
+	pgstat_drop_matching_entries(match_inj_entries, DummyDatum);
 
 	PG_RETURN_VOID();
 }
diff --git a/src/test/modules/plsample/plsample.c b/src/test/modules/plsample/plsample.c
index 78802a94f62..e07482e5736 100644
--- a/src/test/modules/plsample/plsample.c
+++ b/src/test/modules/plsample/plsample.c
@@ -38,7 +38,7 @@ static HeapTuple plsample_trigger_handler(PG_FUNCTION_ARGS);
 Datum
 plsample_call_handler(PG_FUNCTION_ARGS)
 {
-	Datum		retval = (Datum) 0;
+	Datum		retval = DummyDatum;
 
 	/*
 	 * Many languages will require cleanup that happens even in the event of
diff --git a/src/test/modules/test_ddl_deparse/test_ddl_deparse.c b/src/test/modules/test_ddl_deparse/test_ddl_deparse.c
index 193669f2bc1..7c3fb040afe 100644
--- a/src/test/modules/test_ddl_deparse/test_ddl_deparse.c
+++ b/src/test/modules/test_ddl_deparse/test_ddl_deparse.c
@@ -327,5 +327,5 @@ get_altertable_subcmdinfo(PG_FUNCTION_ARGS)
 		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
 	}
 
-	return (Datum) 0;
+	PG_RETURN_DUMMY();
 }
diff --git a/src/test/modules/test_regex/test_regex.c b/src/test/modules/test_regex/test_regex.c
index 2548a0ef7b1..2d3fe51ddae 100644
--- a/src/test/modules/test_regex/test_regex.c
+++ b/src/test/modules/test_regex/test_regex.c
@@ -717,7 +717,7 @@ build_test_match_result(test_regex_ctx *matchctx)
 		}
 		else if (so < 0 || eo < 0)
 		{
-			elems[i] = (Datum) 0;
+			//elems[i] = DummyDatum;
 			nulls[i] = true;
 		}
 		else if (buf)
-- 
2.50.1

#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: Peter Eisentraut (#1)
Re: Datum as struct

Peter Eisentraut <peter@eisentraut.org> writes:

But I think the patches 0001 through 0005 are useful now.
I tested this against the original patch in [0]. It fixes some of the
issues discussed there but not all of them.

I looked through this. I think 0001-0003 are unconditionally
improvements and you should just commit them. Many of the
pointer-related changes are identical to ones that I had arrived at
while working on cleaning up the gcc warnings from my 8-byte-Datum
patch, so this would create merge conflicts with that patch, and
getting these changes in would make that one shorter.

I do have one review comment on 0003: in
brin_minmax_multi_distance_numeric, you wrote

-	PG_RETURN_FLOAT8(DirectFunctionCall1(numeric_float8, d));
+	PG_RETURN_FLOAT8(DatumGetFloat8(DirectFunctionCall1(numeric_float8, d)));

Another way to do that could be

PG_RETURN_DATUM(DirectFunctionCall1(numeric_float8, d));

I'm not sure we should expect the compiler to be able to elide
the conversions to float8 and back, so I prefer the second way.

Also I see a "// XXX" in pg_get_aios, which I guess is a note
to confirm the data type to use for ioh_id?

My only reservation about 0004 is whether we want to do it like
this, or with the separate "_D" functions that I proposed in
the other thread. Right now the vote seems to be 2 to 1 for
adding DatumGetPointer calls, so unless there are more votes
you should go ahead with 0004 as well.

No objection to 0005 either.

I agree that 0006 is not something we want to commit. Aside
from all the replacements for "(Datum) 0" --- which'd be fine
I guess if there weren't so darn many --- it seems to me that
bits like this are punching too many holes in the abstraction:

-	if (PointerGetDatum(key) != entry->key)
+	if (PointerGetDatum(key).value != entry->key.value)

It'd probably be an improvement to code that like

if ((Pointer) key != DatumGetPointer(entry->key))

which matches the way we do things in many other places.
But in general any direct reference to .value outside the
DatumGetFoo/FooGetDatum functions seems like an abstraction fail.

However, the sheer number of quasi-cosmetic issues you found
this way gives me pause. If we don't have something like
0006 available for test purposes, more bugs of the same
ilk are surely going to creep in.

regards, tom lane

#3Michael Paquier
michael@paquier.xyz
In reply to: Tom Lane (#2)
Re: Datum as struct

On Thu, Jul 31, 2025 at 01:17:54PM -0400, Tom Lane wrote:

My only reservation about 0004 is whether we want to do it like
this, or with the separate "_D" functions that I proposed in
the other thread. Right now the vote seems to be 2 to 1 for
adding DatumGetPointer calls, so unless there are more votes
you should go ahead with 0004 as well.

Quote from this message:
/messages/by-id/1520348.1753891591@sss.pgh.pa.us

And relevant paragraph:

I think the way forward here is to tackle that head-on and split the
top-level macros into two static inlines, along the lines of
VARDATA(Pointer ptr) and VARDATA_D(Datum dat) where the _D versions
are simply DatumGetPointer and then call the non-D versions.

Will reply on this thread with an option. Spoiler: I have mixed
feelings about the addition of the _D flavors over the additions of
DatumGetPointer() in the existing calls.

@@ -144,7 +144,7 @@ toast_save_datum(Relation rel, Datum value,
int num_indexes;
int validIndex;

-    Assert(!VARATT_IS_EXTERNAL(value));
+    Assert(!VARATT_IS_EXTERNAL(dval));
[...]
+++ b/src/backend/replication/logical/proto.c
             if (isnull[i])
                 continue;
-            else if (VARATT_IS_EXTERNAL_ONDISK(value))
+            else if (VARATT_IS_EXTERNAL_ONDISK(DatumGetPointer(value)))
                 toast_delete_datum(rel, value, is_speculative);
[...]
+++ b/src/backend/replication/logical/proto.c
-		if (att->attlen == -1 && VARATT_IS_EXTERNAL_ONDISK(values[i]))
+		if (att->attlen == -1 && VARATT_IS_EXTERNAL_ONDISK(DatumGetPointer(values[i])))

I was wondering the impact of this change in terms of the refactoring
work I've been for TOAST at [1]/messages/by-id/aFOnKHG7Wn-Srnpv@paquier.xyz -- Michael, which is something that I'm also
planning to get in committable shape very soon to ease the addition of
more on-disk external TOAST pointers. When I've looked at the
problem, I've found the current non-distinction between Datums and
varlenas confusing, so forcing more control with types is an
improvement IMO. At the end the impact is I think null, my stuff uses
varlenas in the refactored code rather than Datums.

[1]: /messages/by-id/aFOnKHG7Wn-Srnpv@paquier.xyz -- Michael
--
Michael

#4Peter Eisentraut
peter@eisentraut.org
In reply to: Tom Lane (#2)
1 attachment(s)
pgaio_io_get_id() type (was Re: Datum as struct)

On 31.07.25 19:17, Tom Lane wrote:

Also I see a "// XXX" in pg_get_aios, which I guess is a note
to confirm the data type to use for ioh_id?

Yes, the stuff returned from pgaio_io_get_id() should be int, but some
code uses uint32, and also UINT32_MAX as a special marker. Here is a
patch that tries to straighten that out by using int consistently and -1
as a special marker.

Attachments:

0001-Use-consistent-type-for-pgaio_io_get_id-result.patchtext/plain; charset=UTF-8; name=0001-Use-consistent-type-for-pgaio_io_get_id-result.patchDownload
From e1bb97e13af226cd15c9a59929aef48bc92c4ac2 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Tue, 5 Aug 2025 19:16:38 +0200
Subject: [PATCH] Use consistent type for pgaio_io_get_id() result

The result of pgaio_io_get_id() was being assigned to a mix of int and
uint32 variables.  This fixes it to use int consistently, which seems
the most correct.  Also change the queue empty special value in
method_worker.c to -1 from UINT32_MAX.
---
 src/backend/storage/aio/aio_funcs.c     |  4 ++--
 src/backend/storage/aio/method_worker.c | 14 +++++++-------
 2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/src/backend/storage/aio/aio_funcs.c b/src/backend/storage/aio/aio_funcs.c
index 584e683371a..34f8f632733 100644
--- a/src/backend/storage/aio/aio_funcs.c
+++ b/src/backend/storage/aio/aio_funcs.c
@@ -56,7 +56,7 @@ pg_get_aios(PG_FUNCTION_ARGS)
 	for (uint64 i = 0; i < pgaio_ctl->io_handle_count; i++)
 	{
 		PgAioHandle *live_ioh = &pgaio_ctl->io_handles[i];
-		uint32		ioh_id = pgaio_io_get_id(live_ioh);
+		int			ioh_id = pgaio_io_get_id(live_ioh);
 		Datum		values[PG_GET_AIOS_COLS] = {0};
 		bool		nulls[PG_GET_AIOS_COLS] = {0};
 		ProcNumber	owner;
@@ -152,7 +152,7 @@ pg_get_aios(PG_FUNCTION_ARGS)
 			nulls[0] = false;
 
 		/* column: IO's id */
-		values[1] = ioh_id;
+		values[1] = Int32GetDatum(ioh_id);
 
 		/* column: IO's generation */
 		values[2] = Int64GetDatum(start_generation);
diff --git a/src/backend/storage/aio/method_worker.c b/src/backend/storage/aio/method_worker.c
index bf8f77e6ff6..b5ac073a910 100644
--- a/src/backend/storage/aio/method_worker.c
+++ b/src/backend/storage/aio/method_worker.c
@@ -58,7 +58,7 @@ typedef struct PgAioWorkerSubmissionQueue
 	uint32		mask;
 	uint32		head;
 	uint32		tail;
-	uint32		sqes[FLEXIBLE_ARRAY_MEMBER];
+	int			sqes[FLEXIBLE_ARRAY_MEMBER];
 } PgAioWorkerSubmissionQueue;
 
 typedef struct PgAioWorkerSlot
@@ -107,7 +107,7 @@ pgaio_worker_queue_shmem_size(int *queue_size)
 	*queue_size = pg_nextpower2_32(io_worker_queue_size);
 
 	return offsetof(PgAioWorkerSubmissionQueue, sqes) +
-		sizeof(uint32) * *queue_size;
+		sizeof(int) * *queue_size;
 }
 
 static size_t
@@ -198,15 +198,15 @@ pgaio_worker_submission_queue_insert(PgAioHandle *ioh)
 	return true;
 }
 
-static uint32
+static int
 pgaio_worker_submission_queue_consume(void)
 {
 	PgAioWorkerSubmissionQueue *queue;
-	uint32		result;
+	int			result;
 
 	queue = io_worker_submission_queue;
 	if (queue->tail == queue->head)
-		return UINT32_MAX;		/* empty */
+		return -1;				/* empty */
 
 	result = queue->sqes[queue->tail];
 	queue->tail = (queue->tail + 1) & (queue->size - 1);
@@ -470,7 +470,7 @@ IoWorkerMain(const void *startup_data, size_t startup_data_len)
 		 * to ensure that we don't see an outdated data in the handle.
 		 */
 		LWLockAcquire(AioWorkerSubmissionQueueLock, LW_EXCLUSIVE);
-		if ((io_index = pgaio_worker_submission_queue_consume()) == UINT32_MAX)
+		if ((io_index = pgaio_worker_submission_queue_consume()) == -1)
 		{
 			/*
 			 * Nothing to do.  Mark self idle.
@@ -500,7 +500,7 @@ IoWorkerMain(const void *startup_data, size_t startup_data_len)
 		for (int i = 0; i < nlatches; ++i)
 			SetLatch(latches[i]);
 
-		if (io_index != UINT32_MAX)
+		if (io_index != -1)
 		{
 			PgAioHandle *ioh = NULL;
 
-- 
2.50.1

#5Peter Eisentraut
peter@eisentraut.org
In reply to: Peter Eisentraut (#1)
Re: Datum as struct
diff --git a/src/backend/utils/adt/timestamp.c 

b/src/backend/utils/adt/timestamp.c

index 25cff56c3d0..e640b48205b 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -4954,7 +4954,7 @@ timestamptz_trunc_internal(text *units, 

TimestampTz timestamp, pg_tz *tzp)

case DTK_SECOND:
case DTK_MILLISEC:
case DTK_MICROSEC:
- PG_RETURN_TIMESTAMPTZ(timestamp);
+ return timestamp;
break;

default:

This one is an actual bug. With int64-pass-by-reference,
PG_RETURN_TIMESTAMPTZ() returns a newly allocated address. This is
easily reproduced by

SELECT date_trunc( 'week', timestamp with time zone 'infinity' );

which will return a random value on 32-bit systems. (It correctly
returns 'infinity' otherwise.)

I'll see about backpatching fixes for this.

#6Peter Eisentraut
peter@eisentraut.org
In reply to: Peter Eisentraut (#5)
Re: Datum as struct

On 05.08.25 20:06, Peter Eisentraut wrote:

diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/ 

adt/timestamp.c

index 25cff56c3d0..e640b48205b 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -4954,7 +4954,7 @@ timestamptz_trunc_internal(text *units, 

TimestampTz timestamp, pg_tz *tzp)

                  case DTK_SECOND:
                  case DTK_MILLISEC:
                  case DTK_MICROSEC:
-                    PG_RETURN_TIMESTAMPTZ(timestamp);
+                    return timestamp;
                     break;

                 default:

This one is an actual bug.  With int64-pass-by-reference,
PG_RETURN_TIMESTAMPTZ() returns a newly allocated address.  This is
easily reproduced by

SELECT date_trunc( 'week', timestamp with time zone 'infinity' );

which will return a random value on 32-bit systems.  (It correctly
returns 'infinity' otherwise.)

I'll see about backpatching fixes for this.

This is new in PG18, so I'm continuing the discussion in the original
thread:
/messages/by-id/CAAvxfHc4084dGzEJR0_pBZkDuqbPGc5wn7gK_M0XR_kRiCdUJQ@mail.gmail.com

#7Tom Lane
tgl@sss.pgh.pa.us
In reply to: Peter Eisentraut (#6)
Re: Datum as struct

Peter Eisentraut <peter@eisentraut.org> writes:

On 05.08.25 20:06, Peter Eisentraut wrote:

-                    PG_RETURN_TIMESTAMPTZ(timestamp);
+                    return timestamp;

This one is an actual bug.

I took another look through this patch series and realized that this
bit from 0003 is also a live bug that should be back-patched, for
exactly the same reason as with the above:

diff --git a/contrib/intarray/_int_selfuncs.c b/contrib/intarray/_int_selfuncs.c
index 6c3b7ace146..9bf64486242 100644
--- a/contrib/intarray/_int_selfuncs.c
+++ b/contrib/intarray/_int_selfuncs.c
@@ -177,7 +177,7 @@ _int_matchsel(PG_FUNCTION_ARGS)
 	if (query->size == 0)
 	{
 		ReleaseVariableStats(vardata);
-		return (Selectivity) 0.0;
+		PG_RETURN_FLOAT8(0.0);
 	}

/*

I think that on a 32-bit machine this would actually result in a
null-pointer core dump, since the 0.0 would be coerced to a zero
Datum value. The line is not reached in our regression tests,
and given the lack of field complaints, it must be hard to reach
in normal use too. Or 32-bit machines are deader than I thought.

regards, tom lane

#8Tom Lane
tgl@sss.pgh.pa.us
In reply to: Tom Lane (#7)
Re: Datum as struct

I wrote:

I think that on a 32-bit machine this would actually result in a
null-pointer core dump, since the 0.0 would be coerced to a zero
Datum value. The line is not reached in our regression tests,
and given the lack of field complaints, it must be hard to reach
in normal use too. Or 32-bit machines are deader than I thought.

On closer inspection, it's unreachable because bqarr_in won't
accept an empty query, and there is no other function that will
create query_int values. So probably it's not worth the trouble
to back-patch.

regards, tom lane

#9Peter Eisentraut
peter@eisentraut.org
In reply to: Tom Lane (#8)
Re: Datum as struct

On 07.08.25 03:55, Tom Lane wrote:

I wrote:

I think that on a 32-bit machine this would actually result in a
null-pointer core dump, since the 0.0 would be coerced to a zero
Datum value. The line is not reached in our regression tests,
and given the lack of field complaints, it must be hard to reach
in normal use too. Or 32-bit machines are deader than I thought.

On closer inspection, it's unreachable because bqarr_in won't
accept an empty query, and there is no other function that will
create query_int values. So probably it's not worth the trouble
to back-patch.

I ended up backpatching this, since it was easy enough and I didn't want
to leave such patently broken code lie around. And it will allow us to
label the remaining cleanup patches as "harmless". I'll go commit those
to master next.

#10Andres Freund
andres@anarazel.de
In reply to: Peter Eisentraut (#4)
Re: pgaio_io_get_id() type (was Re: Datum as struct)

Hi,

On 2025-08-05 19:20:20 +0200, Peter Eisentraut wrote:

On 31.07.25 19:17, Tom Lane wrote:

Also I see a "// XXX" in pg_get_aios, which I guess is a note
to confirm the data type to use for ioh_id?

Yes, the stuff returned from pgaio_io_get_id() should be int, but some code
uses uint32, and also UINT32_MAX as a special marker. Here is a patch that
tries to straighten that out by using int consistently and -1 as a special
marker.

From e1bb97e13af226cd15c9a59929aef48bc92c4ac2 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Tue, 5 Aug 2025 19:16:38 +0200
Subject: [PATCH] Use consistent type for pgaio_io_get_id() result

The result of pgaio_io_get_id() was being assigned to a mix of int and
uint32 variables. This fixes it to use int consistently, which seems
the most correct. Also change the queue empty special value in
method_worker.c to -1 from UINT32_MAX.

WFM. I guess I could see some value going with an unsigned value instead of a
signed one, but it really doesn't matter...

Greetings,

Andres

#11Andres Freund
andres@anarazel.de
In reply to: Peter Eisentraut (#1)
Re: Datum as struct

Hi,

On 2025-07-31 16:02:35 +0200, Peter Eisentraut wrote:

Another draft patch set that I had lying around that was mentioned in [0].

Nice, thanks for doing that. I tried this a few years back and was scared away
by the churn, but I think it's well worth tackling.

One thing that would be an interesting follow-up would be to make the struct
not just carry the datum, but also the type of the field, to be filled in by
tuple deforming and the *GetDatum() functions. Then we could assert that the
correct DatumGet*() functions are used. I think that'd allow us to detect a
rather large number of issues that we currently aren't finding - I'd bet a
review of a large patchset that we'd fine a number of old bugs.

From 869185199e7a7b711afb5b51834cbb0691ee8223 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Thu, 31 Jul 2025 15:18:02 +0200
Subject: [PATCH v1 3/6] Add missing Datum conversions

Add various missing conversions from and to Datum. The previous code
mostly relied on implicit conversions or its own explicit casts
instead of using the correct DatumGet*() or *GetDatum() functions.

diff --git a/contrib/btree_gist/btree_utils_num.c b/contrib/btree_gist/btree_utils_num.c
index 346ee837d75..446fa930b92 100644
--- a/contrib/btree_gist/btree_utils_num.c
+++ b/contrib/btree_gist/btree_utils_num.c
@@ -119,38 +119,38 @@ gbt_num_fetch(GISTENTRY *entry, const gbtree_ninfo *tinfo)
switch (tinfo->t)
{
case gbt_t_bool:
-			datum = BoolGetDatum(*(bool *) entry->key);
+			datum = BoolGetDatum(*(bool *) DatumGetPointer(entry->key));
break;
case gbt_t_int2:
-			datum = Int16GetDatum(*(int16 *) entry->key);
+			datum = Int16GetDatum(*(int16 *) DatumGetPointer(entry->key));
break;
case gbt_t_int4:
-			datum = Int32GetDatum(*(int32 *) entry->key);
+			datum = Int32GetDatum(*(int32 *) DatumGetPointer(entry->key));
break;
case gbt_t_int8:
-			datum = Int64GetDatum(*(int64 *) entry->key);
+			datum = Int64GetDatum(*(int64 *) DatumGetPointer(entry->key));
break;
case gbt_t_oid:
case gbt_t_enum:
-			datum = ObjectIdGetDatum(*(Oid *) entry->key);
+			datum = ObjectIdGetDatum(*(Oid *) DatumGetPointer(entry->key));
break;
case gbt_t_float4:
-			datum = Float4GetDatum(*(float4 *) entry->key);
+			datum = Float4GetDatum(*(float4 *) DatumGetPointer(entry->key));
break;
case gbt_t_float8:
-			datum = Float8GetDatum(*(float8 *) entry->key);
+			datum = Float8GetDatum(*(float8 *) DatumGetPointer(entry->key));
break;
case gbt_t_date:
-			datum = DateADTGetDatum(*(DateADT *) entry->key);
+			datum = DateADTGetDatum(*(DateADT *) DatumGetPointer(entry->key));
break;
case gbt_t_time:
-			datum = TimeADTGetDatum(*(TimeADT *) entry->key);
+			datum = TimeADTGetDatum(*(TimeADT *) DatumGetPointer(entry->key));
break;
case gbt_t_ts:
-			datum = TimestampGetDatum(*(Timestamp *) entry->key);
+			datum = TimestampGetDatum(*(Timestamp *) DatumGetPointer(entry->key));
break;
case gbt_t_cash:
-			datum = CashGetDatum(*(Cash *) entry->key);
+			datum = CashGetDatum(*(Cash *) DatumGetPointer(entry->key));
break;
default:
datum = entry->key;

Would probably be more readable if you put DatumGetPointer(entry->key) into a
local variable...

From dfd9e4b16e979ac52be682d8c093f883da8d7ba2 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Thu, 31 Jul 2025 15:18:02 +0200
Subject: [PATCH v1 5/6] Fix various hash function uses

These instances were using Datum-returning functions where a
lower-level function returning uint32 would be more appropriate.

Indeed.

From 81e56922fe429fae6ebc33b2f518ef88b00ffc42 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Thu, 31 Jul 2025 15:18:02 +0200
Subject: [PATCH v1 6/6] WIP: Datum as struct

This changes Datum to a struct so that you can no longer rely on it
being implicitly convertable to other C types.

(I only skimmed this very very briefly)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index f98805fb5f7..e56e0db97c9 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -653,7 +653,7 @@ dblink_fetch(PG_FUNCTION_ARGS)
{
dblink_res_error(conn, conname, res, fail,
"while fetching from cursor \"%s\"", curname);
-		return (Datum) 0;
+		PG_RETURN_DUMMY();
}
else if (PQresultStatus(res) == PGRES_COMMAND_OK)
{
@@ -665,7 +665,7 @@ dblink_fetch(PG_FUNCTION_ARGS)
}
materializeResult(fcinfo, conn, res);
-	return (Datum) 0;
+	PG_RETURN_DUMMY();
}

/*

Probably worth splitting this type of change out into its own commit, this
is a pretty large change, and that could be done independently.

diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index 9c53877c4a5..d059b31231f 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1113,7 +1113,7 @@ hstore_populate_record(PG_FUNCTION_ARGS)
{
for (i = 0; i < ncolumns; ++i)
{
-			values[i] = (Datum) 0;
+			values[i] = DummyDatum;
nulls[i] = true;
}
}

I don't think I like DummyDatum very much, but I don't really have a better
suggestion. It could be worth having a separate NullPointerDatum? Should
also probably be its own patch.

One thing that'd be nice is to mark the value as uninitialized, so that
valgrind etc could find cases where we rely on these dummy datums.

diff --git a/contrib/ltree/_ltree_gist.c b/contrib/ltree/_ltree_gist.c
index 286ad24fbe8..2d71cea7e5a 100644
--- a/contrib/ltree/_ltree_gist.c
+++ b/contrib/ltree/_ltree_gist.c
@@ -84,7 +84,7 @@ _ltree_compress(PG_FUNCTION_ARGS)
entry->rel, entry->page,
entry->offset, false);
}
-	else if (!LTG_ISALLTRUE(entry->key))
+	else if (!LTG_ISALLTRUE(entry->key.value))

This should be DatumGet*(), no?

diff --git a/contrib/sepgsql/label.c b/contrib/sepgsql/label.c
index 996ce174454..5d57563ecb7 100644
--- a/contrib/sepgsql/label.c
+++ b/contrib/sepgsql/label.c
@@ -330,7 +330,7 @@ sepgsql_fmgr_hook(FmgrHookEventType event,
stack = palloc(sizeof(*stack));
stack->old_label = NULL;
stack->new_label = sepgsql_avc_trusted_proc(flinfo->fn_oid);
-				stack->next_private = 0;
+				stack->next_private.value = 0;

MemoryContextSwitchTo(oldcxt);

Probably should use DummyDatum.

Greetings,

Andres Freund

#12Tom Lane
tgl@sss.pgh.pa.us
In reply to: Andres Freund (#11)
Re: Datum as struct

Andres Freund <andres@anarazel.de> writes:

On 2025-07-31 16:02:35 +0200, Peter Eisentraut wrote:

diff --git a/contrib/ltree/_ltree_gist.c b/contrib/ltree/_ltree_gist.c
index 286ad24fbe8..2d71cea7e5a 100644
--- a/contrib/ltree/_ltree_gist.c
+++ b/contrib/ltree/_ltree_gist.c
@@ -84,7 +84,7 @@ _ltree_compress(PG_FUNCTION_ARGS)
entry->rel, entry->page,
entry->offset, false);
}
-	else if (!LTG_ISALLTRUE(entry->key))
+	else if (!LTG_ISALLTRUE(entry->key.value))

This should be DatumGet*(), no?

Indeed. I was just rebasing my 8-byte-Datum patch onto HEAD, and
noted this and one or two other places still missing DatumGetPointer.
I plan to go ahead and commit a cleanup patch with those fixes and
s/(Datum) NULL/(Datum) 0/g as soon as I've finished testing.

FWIW, I don't love the "DummyDatum" name either. Maybe InvalidDatum?

regards, tom lane

#13Peter Eisentraut
peter@eisentraut.org
In reply to: Tom Lane (#12)
Re: Datum as struct

On 08.08.25 22:55, Tom Lane wrote:

FWIW, I don't love the "DummyDatum" name either. Maybe InvalidDatum?

I specifically did not use InvalidDatum because, for example, the result
of Int32GetDatum(0) is by no means "invalid". Maybe something like
NullDatum or VoidDatum?

A few related thoughts:

The calls to PG_RETURN_DUMMY() in my patch are in set-returning
functions. I thought maybe a real API macro would be nice here, like
PG_RETURN_SRF_DONE().

Many changes are in the arguments of on_*_exit() functions. I always
thought it was weird layering to use Datum at that level. I mean, would
on_proc_exit(foo, Int64GetDatum(val)) even work correctly on 32-bit
platforms?

Another common coding pattern is something like

if (isnull)
{
d = (Datum) 0;
n = true;
}
else
{
d = actualvalue;
n = false;
}

sometimes with a comment /* keep compiler quiet */ or /* redundant, but
safe */.

I wonder whether it would in general be better to not initialize "d" in
the first case, allowing perhaps static analyzers to detect invalid
accesses later on. On the other hand, this might confuse regular
compilers into warnings, as the comments suggest.

So maybe finding some higher-level changes in these areas could reduce
the churn in the remaining patch significantly.

#14Peter Eisentraut
peter@eisentraut.org
In reply to: Andres Freund (#11)
Re: Datum as struct

On 08.08.25 22:30, Andres Freund wrote:

One thing that would be an interesting follow-up would be to make the struct
not just carry the datum, but also the type of the field, to be filled in by
tuple deforming and the *GetDatum() functions. Then we could assert that the
correct DatumGet*() functions are used. I think that'd allow us to detect a
rather large number of issues that we currently aren't finding

That would make Datum >=9 bytes? Is that something we would need to
worry about in terms of performance?

#15Tom Lane
tgl@sss.pgh.pa.us
In reply to: Peter Eisentraut (#14)
Re: Datum as struct

Peter Eisentraut <peter@eisentraut.org> writes:

On 08.08.25 22:30, Andres Freund wrote:

One thing that would be an interesting follow-up would be to make the struct
not just carry the datum, but also the type of the field, to be filled in by
tuple deforming and the *GetDatum() functions. Then we could assert that the
correct DatumGet*() functions are used. I think that'd allow us to detect a
rather large number of issues that we currently aren't finding

That would make Datum >=9 bytes? Is that something we would need to
worry about in terms of performance?

It'd have to be a cassert-like option, not something you'd enable in
production.

regards, tom lane

#16Peter Eisentraut
peter@eisentraut.org
In reply to: Andres Freund (#10)
Re: pgaio_io_get_id() type (was Re: Datum as struct)

On 08.08.25 22:07, Andres Freund wrote:

On 2025-08-05 19:20:20 +0200, Peter Eisentraut wrote:

On 31.07.25 19:17, Tom Lane wrote:

Also I see a "// XXX" in pg_get_aios, which I guess is a note
to confirm the data type to use for ioh_id?

Yes, the stuff returned from pgaio_io_get_id() should be int, but some code
uses uint32, and also UINT32_MAX as a special marker. Here is a patch that
tries to straighten that out by using int consistently and -1 as a special
marker.

From e1bb97e13af226cd15c9a59929aef48bc92c4ac2 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Tue, 5 Aug 2025 19:16:38 +0200
Subject: [PATCH] Use consistent type for pgaio_io_get_id() result

The result of pgaio_io_get_id() was being assigned to a mix of int and
uint32 variables. This fixes it to use int consistently, which seems
the most correct. Also change the queue empty special value in
method_worker.c to -1 from UINT32_MAX.

WFM. I guess I could see some value going with an unsigned value instead of a
signed one, but it really doesn't matter...

I have committed this.