($INBOX_DIR/description missing)  
help / color / mirror / Atom feed
[PATCH 1/8] Get datum from tuple which doesn't contain external data
51+ messages / 3 participants
[nested] [flat]

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--C94crkcyjafcjHxo
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--cvVnyQ+4j833TQvp
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--C94crkcyjafcjHxo
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--cvVnyQ+4j833TQvp
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--cvVnyQ+4j833TQvp
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--C94crkcyjafcjHxo
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--cvVnyQ+4j833TQvp
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--C94crkcyjafcjHxo
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--cvVnyQ+4j833TQvp
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--C94crkcyjafcjHxo
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--cvVnyQ+4j833TQvp
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--C94crkcyjafcjHxo
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--cvVnyQ+4j833TQvp
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--C94crkcyjafcjHxo
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--cvVnyQ+4j833TQvp
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--C94crkcyjafcjHxo
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--cvVnyQ+4j833TQvp
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--C94crkcyjafcjHxo
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--cvVnyQ+4j833TQvp
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--C94crkcyjafcjHxo
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--cvVnyQ+4j833TQvp
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--C94crkcyjafcjHxo
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--cvVnyQ+4j833TQvp
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--C94crkcyjafcjHxo
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--cvVnyQ+4j833TQvp
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--C94crkcyjafcjHxo
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--cvVnyQ+4j833TQvp
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--C94crkcyjafcjHxo
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--cvVnyQ+4j833TQvp
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--C94crkcyjafcjHxo
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--cvVnyQ+4j833TQvp
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--C94crkcyjafcjHxo
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--cvVnyQ+4j833TQvp
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--C94crkcyjafcjHxo
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--cvVnyQ+4j833TQvp
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--C94crkcyjafcjHxo
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--cvVnyQ+4j833TQvp
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--C94crkcyjafcjHxo
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--cvVnyQ+4j833TQvp
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--C94crkcyjafcjHxo
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--cvVnyQ+4j833TQvp
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--C94crkcyjafcjHxo
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--cvVnyQ+4j833TQvp
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--C94crkcyjafcjHxo
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--cvVnyQ+4j833TQvp
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--C94crkcyjafcjHxo
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--cvVnyQ+4j833TQvp
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* [PATCH 1/8] Get datum from tuple which doesn't contain external data
@ 2021-03-04 08:00  Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2021-03-04 08:00 UTC (permalink / raw)

Currently, we use HeapTupleGetDatum and HeapTupleHeaderGetDatum whenever
we need to convert a tuple to datum.  Introduce another version of these
routine HeapTupleGetRawDatum and HeapTupleHeaderGetRawDatum respectively
so that all the callers who doesn't expect any external data in the tuple
can call these new routines. Likewise similar treatment for
heap_copy_tuple_as_datum and PG_RETURN_HEAPTUPLEHEADER as well.

Dilip Kumar based on the idea by Robert Haas
---
 contrib/dblink/dblink.c                         |  2 +-
 contrib/hstore/hstore_io.c                      |  4 ++--
 contrib/hstore/hstore_op.c                      |  2 +-
 contrib/old_snapshot/time_mapping.c             |  2 +-
 contrib/pageinspect/brinfuncs.c                 |  2 +-
 contrib/pageinspect/btreefuncs.c                |  6 +++---
 contrib/pageinspect/ginfuncs.c                  |  6 +++---
 contrib/pageinspect/gistfuncs.c                 |  2 +-
 contrib/pageinspect/hashfuncs.c                 |  8 ++++----
 contrib/pageinspect/heapfuncs.c                 |  6 +++---
 contrib/pageinspect/rawpage.c                   |  2 +-
 contrib/pg_buffercache/pg_buffercache_pages.c   |  2 +-
 contrib/pg_stat_statements/pg_stat_statements.c |  3 ++-
 contrib/pg_visibility/pg_visibility.c           | 13 ++++++++-----
 contrib/pgcrypto/pgp-pgsql.c                    |  2 +-
 contrib/pgstattuple/pgstatapprox.c              |  2 +-
 contrib/pgstattuple/pgstatindex.c               |  6 +++---
 contrib/pgstattuple/pgstattuple.c               |  2 +-
 contrib/sslinfo/sslinfo.c                       |  2 +-
 src/backend/access/common/heaptuple.c           | 17 +++++++++++++++--
 src/backend/access/transam/commit_ts.c          |  4 ++--
 src/backend/access/transam/multixact.c          |  2 +-
 src/backend/access/transam/twophase.c           |  2 +-
 src/backend/access/transam/xlogfuncs.c          |  2 +-
 src/backend/catalog/objectaddress.c             |  6 +++---
 src/backend/commands/sequence.c                 |  2 +-
 src/backend/executor/execExprInterp.c           | 15 ++++++++++-----
 src/backend/replication/slotfuncs.c             |  8 ++++----
 src/backend/replication/walreceiver.c           |  3 ++-
 src/backend/statistics/mcv.c                    |  2 +-
 src/backend/tsearch/wparser.c                   |  4 ++--
 src/backend/utils/adt/acl.c                     |  2 +-
 src/backend/utils/adt/datetime.c                |  2 +-
 src/backend/utils/adt/genfile.c                 |  2 +-
 src/backend/utils/adt/lockfuncs.c               |  4 ++--
 src/backend/utils/adt/misc.c                    |  4 ++--
 src/backend/utils/adt/partitionfuncs.c          |  2 +-
 src/backend/utils/adt/pgstatfuncs.c             |  6 ++++--
 src/backend/utils/adt/rowtypes.c                |  4 ++--
 src/backend/utils/adt/tsvector_op.c             |  4 ++--
 src/backend/utils/misc/guc.c                    |  2 +-
 src/backend/utils/misc/pg_controldata.c         |  8 ++++----
 src/include/access/htup_details.h               |  1 +
 src/include/fmgr.h                              |  1 +
 src/include/funcapi.h                           | 15 ++++++++++++++-
 src/pl/plperl/plperl.c                          |  4 ++--
 src/pl/tcl/pltcl.c                              |  4 ++--
 src/test/modules/test_predtest/test_predtest.c  |  3 ++-
 48 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3a0beaa88e..5a41116e8e 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -1630,7 +1630,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index b3304ff844..cc7a8e0eef 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1137,14 +1137,14 @@ hstore_populate_record(PG_FUNCTION_ARGS)
 	 * check domain constraints before deciding we're done.
 	 */
 	if (argtype != tupdesc->tdtypeid)
-		domain_check(HeapTupleGetDatum(rettuple), false,
+		domain_check(HeapTupleGetRawDatum(rettuple), false,
 					 argtype,
 					 &my_extra->domain_info,
 					 fcinfo->flinfo->fn_mcxt);
 
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(rettuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(rettuple->t_data);
 }
 
 
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index dd79d01cac..d466f6cc46 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -1067,7 +1067,7 @@ hstore_each(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, dvalues, nulls);
-		res = HeapTupleGetDatum(tuple);
+		res = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
 	}
diff --git a/contrib/old_snapshot/time_mapping.c b/contrib/old_snapshot/time_mapping.c
index 3df07177ed..5d517c8afc 100644
--- a/contrib/old_snapshot/time_mapping.c
+++ b/contrib/old_snapshot/time_mapping.c
@@ -72,7 +72,7 @@ pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
 
 		tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
 		++mapping->current_index;
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c
index 0e3c2deb66..626294685a 100644
--- a/contrib/pageinspect/brinfuncs.c
+++ b/contrib/pageinspect/brinfuncs.c
@@ -366,7 +366,7 @@ brin_metapage_info(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index b7725b572f..f0028e4cc4 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -263,7 +263,7 @@ bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -436,7 +436,7 @@ bt_page_print_tuples(struct user_args *uargs)
 	/* Build and return the result tuple */
 	tuple = heap_form_tuple(uargs->tupd, values, nulls);
 
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /*-------------------------------------------------------
@@ -766,7 +766,7 @@ bt_metap(PG_FUNCTION_ARGS)
 	tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 								   values);
 
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	UnlockReleaseBuffer(buffer);
 	relation_close(rel, AccessShareLock);
diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c
index e425cbcdb8..77dd559c7e 100644
--- a/contrib/pageinspect/ginfuncs.c
+++ b/contrib/pageinspect/ginfuncs.c
@@ -82,7 +82,7 @@ gin_metapage_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 
@@ -150,7 +150,7 @@ gin_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 typedef struct gin_leafpage_items_state
@@ -254,7 +254,7 @@ gin_leafpage_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->seg = GinNextPostingListSegment(cur);
 
diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c
index eb9f6303df..dbf34f87d4 100644
--- a/contrib/pageinspect/gistfuncs.c
+++ b/contrib/pageinspect/gistfuncs.c
@@ -89,7 +89,7 @@ gist_page_opaque_info(PG_FUNCTION_ARGS)
 	/* Build and return the result tuple. */
 	resultTuple = heap_form_tuple(tupdesc, values, nulls);
 
-	return HeapTupleGetDatum(resultTuple);
+	return HeapTupleGetRawDatum(resultTuple);
 }
 
 Datum
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index ff01119474..957ee5bc14 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -273,7 +273,7 @@ hash_page_stats(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
@@ -368,7 +368,7 @@ hash_page_items(PG_FUNCTION_ARGS)
 		values[j] = Int64GetDatum((int64) hashkey);
 
 		tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		uargs->offset = uargs->offset + 1;
 
@@ -499,7 +499,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* ------------------------------------------------
@@ -577,5 +577,5 @@ hash_metapage_info(PG_FUNCTION_ARGS)
 
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
index f6760eb31e..3a050ee88c 100644
--- a/contrib/pageinspect/heapfuncs.c
+++ b/contrib/pageinspect/heapfuncs.c
@@ -282,7 +282,7 @@ heap_page_items(PG_FUNCTION_ARGS)
 
 		/* Build and return the result tuple. */
 		resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
-		result = HeapTupleGetDatum(resultTuple);
+		result = HeapTupleGetRawDatum(resultTuple);
 
 		inter_call_data->offset++;
 
@@ -540,7 +540,7 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 		values[0] = PointerGetDatum(construct_empty_array(TEXTOID));
 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
 		tuple = heap_form_tuple(tupdesc, values, nulls);
-		PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+		PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 	}
 
 	/* build set of raw flags */
@@ -618,5 +618,5 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS)
 
 	/* Returns the record as Datum */
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index 7272b21016..e7aab866b8 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -328,7 +328,7 @@ page_header(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 1bd579fcbb..1fd405e5df 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -230,7 +230,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
 
 		/* Build and return the tuple. */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 62cccbfa44..7eb80d5b78 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -1922,7 +1922,8 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(stats.dealloc);
 	values[1] = TimestampTzGetDatum(stats.stats_reset);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dd0c124e62..43bb2ab852 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -97,7 +97,8 @@ pg_visibility_map(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -156,7 +157,8 @@ pg_visibility(PG_FUNCTION_ARGS)
 
 	relation_close(rel, AccessShareLock);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -197,7 +199,7 @@ pg_visibility_map_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -243,7 +245,7 @@ pg_visibility_rel(PG_FUNCTION_ARGS)
 		info->next++;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -303,7 +305,8 @@ pg_visibility_map_summary(PG_FUNCTION_ARGS)
 	values[0] = Int64GetDatum(all_visible);
 	values[1] = Int64GetDatum(all_frozen);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
diff --git a/contrib/pgcrypto/pgp-pgsql.c b/contrib/pgcrypto/pgp-pgsql.c
index 0536bfb892..333f7fd391 100644
--- a/contrib/pgcrypto/pgp-pgsql.c
+++ b/contrib/pgcrypto/pgp-pgsql.c
@@ -973,7 +973,7 @@ pgp_armor_headers(PG_FUNCTION_ARGS)
 
 		/* build a tuple */
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 }
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 1fe193bb25..147c8d22eb 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -314,5 +314,5 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	values[i++] = Float8GetDatum(stat.free_percent);
 
 	ret = heap_form_tuple(tupdesc, values, nulls);
-	return HeapTupleGetDatum(ret);
+	return HeapTupleGetRawDatum(ret);
 }
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5368bb30f0..7d74c316c7 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -362,7 +362,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
 									   values);
 
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 	}
 
 	return result;
@@ -571,7 +571,7 @@ pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * Build and return the tuple
 	 */
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	return result;
 }
@@ -727,7 +727,7 @@ pgstathashindex(PG_FUNCTION_ARGS)
 	values[7] = Float8GetDatum(free_percent);
 	tuple = heap_form_tuple(tupleDesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /* -------------------------------------------------
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 21fdeff8af..70b8bf0855 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -147,7 +147,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
 	tuple = BuildTupleFromCStrings(attinmeta, values);
 
 	/* make the tuple into a datum */
-	return HeapTupleGetDatum(tuple);
+	return HeapTupleGetRawDatum(tuple);
 }
 
 /* ----------
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 30cae0bb98..53801e92cd 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -460,7 +460,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
 
 		/* Build tuple */
 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		if (BIO_free(membuf) != 1)
 			elog(ERROR, "could not free OpenSSL BIO structure");
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 0b56b0fa5a..c36c283253 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -983,8 +983,6 @@ heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
 Datum
 heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 {
-	HeapTupleHeader td;
-
 	/*
 	 * If the tuple contains any external TOAST pointers, we have to inline
 	 * those fields to meet the conventions for composite-type Datums.
@@ -993,6 +991,21 @@ heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
 		return toast_flatten_tuple_to_datum(tuple->t_data,
 											tuple->t_len,
 											tupleDesc);
+	else
+		return heap_copy_tuple_as_raw_datum(tuple, tupleDesc);
+}
+
+/* ----------------
+ *		heap_copy_tuple_as_raw_datum
+ *
+ *		copy a tuple as a composite-type Datum, but the input tuple should not
+ *		contain any external data.
+ * ----------------
+ */
+Datum
+heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc)
+{
+	HeapTupleHeader td;
 
 	/*
 	 * Fast path for easy case: just make a palloc'd copy and insert the
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 48e8d66286..015c84179e 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -469,7 +469,7 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -518,7 +518,7 @@ pg_xact_commit_timestamp_origin(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1f9f1a1fa1..b44066a4eb 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3399,7 +3399,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 
 		multi->iter++;
 		pfree(values[0]);
-		SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funccxt, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funccxt);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6023e7c16f..3f48597c2a 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -787,7 +787,7 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
 		values[4] = ObjectIdGetDatum(proc->databaseId);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index d8c5bf6dc2..53f84de41c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -487,7 +487,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
 	 */
 	resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
 
-	result = HeapTupleGetDatum(resultHeapTuple);
+	result = HeapTupleGetRawDatum(resultHeapTuple);
 
 	PG_RETURN_DATUM(result);
 }
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6d88b690d8..7cd62e70b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2355,7 +2355,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4233,7 +4233,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
@@ -4304,7 +4304,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 /*
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 0415df9ccb..f566e1e0a5 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1834,7 +1834,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	ReleaseSysCache(pgstuple);
 
-	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+	return HeapTupleGetRawDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
 /*
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6308286d8c..20949a5dec 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3169,8 +3169,13 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 	{
 		/* Full conversion with attribute rearrangement needed */
 		result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
-		/* Result already has appropriate composite-datum header fields */
-		*op->resvalue = HeapTupleGetDatum(result);
+
+		/*
+		 * Result already has appropriate composite-datum header fields. The
+		 * input was a composite type so we aren't expecting to have to flatten
+		 * any toasted fields so directly call HeapTupleGetRawDatum.
+		 */
+		*op->resvalue = HeapTupleGetRawDatum(result);
 	}
 	else
 	{
@@ -3181,10 +3186,10 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext
 		 * for this since it will both make the physical copy and insert the
 		 * correct composite header fields.  Note that we aren't expecting to
 		 * have to flatten any toasted fields: the input was a composite
-		 * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
-		 * is overkill here, but its check for external fields is cheap.
+		 * datum, so it shouldn't contain any.  So we can directly call
+		 * heap_copy_tuple_as_raw_datum().
 		 */
-		*op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
+		*op->resvalue = heap_copy_tuple_as_raw_datum(&tmptup, outdesc);
 	}
 }
 
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 9817b44113..f92628bc59 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -106,7 +106,7 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
@@ -205,7 +205,7 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
 	memset(nulls, 0, sizeof(nulls));
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	/* ok, slot is now fully created, mark it as persistent if needed */
 	if (!temporary)
@@ -689,7 +689,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
 	nulls[1] = false;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	PG_RETURN_DATUM(result);
 }
@@ -911,7 +911,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
 		nulls[1] = true;
 
 	tuple = heap_form_tuple(tupdesc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	ReplicationSlotRelease();
 
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index e5f8a06fea..f973aea8e5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1420,5 +1420,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
 	}
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
diff --git a/src/backend/statistics/mcv.c b/src/backend/statistics/mcv.c
index abbc1f1ba8..115131c707 100644
--- a/src/backend/statistics/mcv.c
+++ b/src/backend/statistics/mcv.c
@@ -1450,7 +1450,7 @@ pg_stats_ext_mcvlist_items(PG_FUNCTION_ARGS)
 		tuple = heap_form_tuple(funcctx->attinmeta->tupdesc, values, nulls);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c
index 71882dced9..633c90d08d 100644
--- a/src/backend/tsearch/wparser.c
+++ b/src/backend/tsearch/wparser.c
@@ -97,7 +97,7 @@ tt_process_call(FuncCallContext *funcctx)
 		values[2] = st->list[st->cur].descr;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		pfree(values[2]);
@@ -236,7 +236,7 @@ prs_process_call(FuncCallContext *funcctx)
 		sprintf(tid, "%d", st->list[st->cur].type);
 		values[1] = st->list[st->cur].lexeme;
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[1]);
 		st->cur++;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index c7f029e218..5871c0b404 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1804,7 +1804,7 @@ aclexplode(PG_FUNCTION_ARGS)
 			MemSet(nulls, 0, sizeof(nulls));
 
 			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-			result = HeapTupleGetDatum(tuple);
+			result = HeapTupleGetRawDatum(tuple);
 
 			SRF_RETURN_NEXT(funcctx, result);
 		}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 350b0c55ea..ce11554b3b 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4776,7 +4776,7 @@ pg_timezone_abbrevs(PG_FUNCTION_ARGS)
 	(*pindex)++;
 
 	tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-	result = HeapTupleGetDatum(tuple);
+	result = HeapTupleGetRawDatum(tuple);
 
 	SRF_RETURN_NEXT(funcctx, result);
 }
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 169ddf8d76..d3d386b748 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -454,7 +454,7 @@ pg_stat_file(PG_FUNCTION_ARGS)
 
 	pfree(filename);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(tuple->t_data);
 }
 
 /*
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 97f0265c12..081844939b 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -344,7 +344,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 			nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
@@ -415,7 +415,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		nulls[15] = true;
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7e..57e0ea09a3 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -484,7 +484,7 @@ pg_get_keywords(PG_FUNCTION_ARGS)
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
@@ -562,7 +562,7 @@ pg_get_catalog_foreign_keys(PG_FUNCTION_ARGS)
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
 
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 
 	SRF_RETURN_DONE(funcctx);
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index 03660d5db6..6915939f43 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -159,7 +159,7 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 		values[3] = Int32GetDatum(level);
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 		SRF_RETURN_NEXT(funcctx, result);
 	}
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 5102227a60..b93ad73241 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1856,7 +1856,8 @@ pg_stat_get_wal(PG_FUNCTION_ARGS)
 	values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /*
@@ -2272,7 +2273,8 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
 
 	/* Returns the record as Datum */
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
 
 /* Get the statistics for the replication slots */
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index 23787a6ae7..079a5af5fb 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -293,7 +293,7 @@ record_in(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
@@ -660,7 +660,7 @@ record_recv(PG_FUNCTION_ARGS)
 	pfree(nulls);
 	ReleaseTupleDesc(tupdesc);
 
-	PG_RETURN_HEAPTUPLEHEADER(result);
+	PG_RETURN_HEAPTUPLEHEADER_RAW(result);
 }
 
 /*
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 9236ebcc8f..6679493247 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -707,7 +707,7 @@ tsvector_unnest(PG_FUNCTION_ARGS)
 		}
 
 		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
-		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetRawDatum(tuple));
 	}
 	else
 	{
@@ -2385,7 +2385,7 @@ ts_process_call(FuncCallContext *funcctx)
 		values[2] = nentry;
 
 		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		pfree(values[0]);
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 855076b1fd..953837085f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9795,7 +9795,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 		tuple = BuildTupleFromCStrings(attinmeta, values);
 
 		/* make the tuple into a datum */
-		result = HeapTupleGetDatum(tuple);
+		result = HeapTupleGetRawDatum(tuple);
 
 		SRF_RETURN_NEXT(funcctx, result);
 	}
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 209a20a882..195c127739 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -73,7 +73,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -204,7 +204,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -257,7 +257,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
 
 Datum
@@ -340,5 +340,5 @@ pg_control_init(PG_FUNCTION_ARGS)
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(htup->t_data);
 }
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index 7c62852e7f..7ac3c2382d 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -790,6 +790,7 @@ extern Datum getmissingattr(TupleDesc tupleDesc,
 extern HeapTuple heap_copytuple(HeapTuple tuple);
 extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
 extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);
+extern Datum heap_copy_tuple_as_raw_datum(HeapTuple tuple, TupleDesc tupleDesc);
 extern HeapTuple heap_form_tuple(TupleDesc tupleDescriptor,
 								 Datum *values, bool *isnull);
 extern HeapTuple heap_modify_tuple(HeapTuple tuple,
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ab7b85c86e..8771ccdac6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -373,6 +373,7 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena *datum);
 #define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 #define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)
+#define PG_RETURN_HEAPTUPLEHEADER_RAW(x)  return HeapTupleHeaderGetRawDatum(x)
 
 
 /*-------------------------------------------------------------------------
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 83e6bc2a1f..8ba7ae211f 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -205,8 +205,13 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  * Datum HeapTupleHeaderGetDatum(HeapTupleHeader tuple) - convert a
  *		HeapTupleHeader to a Datum.
  *
- * Macro declarations:
+ * Macro declarations/inline functions:
+ * HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple) - same as
+ * 		HeapTupleHeaderGetDatum but the input tuple should not contain
+ * 		external varlena
  * HeapTupleGetDatum(HeapTuple tuple) - convert a HeapTuple to a Datum.
+ * HeapTupleGetRawDatum(HeapTuple tuple) - same as HeapTupleGetDatum
+ * 		but the input tuple should not contain external varlena
  *
  * Obsolete routines and macros:
  * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
@@ -218,7 +223,15 @@ extern TupleDesc build_function_result_tupdesc_t(HeapTuple procTuple);
  *----------
  */
 
+static inline Datum
+HeapTupleHeaderGetRawDatum(HeapTupleHeader tuple)
+{
+	Assert(!HeapTupleHeaderHasExternal(tuple));
+	return PointerGetDatum(tuple);
+}
+
 #define HeapTupleGetDatum(tuple)		HeapTupleHeaderGetDatum((tuple)->t_data)
+#define HeapTupleGetRawDatum(tuple)		HeapTupleHeaderGetRawDatum((tuple)->t_data)
 /* obsolete version of above */
 #define TupleGetDatum(_slot, _tuple)	HeapTupleGetDatum(_tuple)
 
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 6299adf71a..cdf79f78e8 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1127,7 +1127,7 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
 {
 	HeapTuple	tup = plperl_build_tuple_result((HV *) SvRV(src), td);
 
-	return HeapTupleGetDatum(tup);
+	return HeapTupleGetRawDatum(tup);
 }
 
 /*
@@ -3334,7 +3334,7 @@ plperl_return_next_internal(SV *sv)
 										  current_call_data->ret_tdesc);
 
 		if (OidIsValid(current_call_data->cdomain_oid))
-			domain_check(HeapTupleGetDatum(tuple), false,
+			domain_check(HeapTupleGetRawDatum(tuple), false,
 						 current_call_data->cdomain_oid,
 						 &current_call_data->cdomain_info,
 						 rsi->econtext->ecxt_per_query_memory);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e11837559d..b4e710a22a 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -1024,7 +1024,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state,
 
 		tup = pltcl_build_tuple_result(interp, resultObjv, resultObjc,
 									   call_state);
-		retval = HeapTupleGetDatum(tup);
+		retval = HeapTupleGetRawDatum(tup);
 	}
 	else
 		retval = InputFunctionCall(&prodesc->result_in_func,
@@ -3235,7 +3235,7 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
 
 	/* if result type is domain-over-composite, check domain constraints */
 	if (call_state->prodesc->fn_retisdomain)
-		domain_check(HeapTupleGetDatum(tuple), false,
+		domain_check(HeapTupleGetRawDatum(tuple), false,
 					 call_state->prodesc->result_typid,
 					 &call_state->prodesc->domain_info,
 					 call_state->prodesc->fn_cxt);
diff --git a/src/test/modules/test_predtest/test_predtest.c b/src/test/modules/test_predtest/test_predtest.c
index 9c0aadd61c..ec83645bbe 100644
--- a/src/test/modules/test_predtest/test_predtest.c
+++ b/src/test/modules/test_predtest/test_predtest.c
@@ -214,5 +214,6 @@ test_predtest(PG_FUNCTION_ARGS)
 	values[6] = BoolGetDatum(s_r_holds);
 	values[7] = BoolGetDatum(w_r_holds);
 
-	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+	PG_RETURN_HEAPTUPLEHEADER_RAW(
+			heap_form_tuple(tupdesc, values, nulls)->t_data);
 }
-- 
2.17.0


--C94crkcyjafcjHxo
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0002-Expand-the-external-data-before-forming-the-tuple.patch"



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* pgsql: Improve performance of subsystems on top of SLRU
@ 2024-02-28 16:07  Alvaro Herrera <[email protected]>
  0 siblings, 1 reply; 51+ messages in thread

From: Alvaro Herrera @ 2024-02-28 16:07 UTC (permalink / raw)
  To: [email protected]

Improve performance of subsystems on top of SLRU

More precisely, what we do here is make the SLRU cache sizes
configurable with new GUCs, so that sites with high concurrency and big
ranges of transactions in flight (resp. multixacts/subtransactions) can
benefit from bigger caches.  In order for this to work with good
performance, two additional changes are made:

1. the cache is divided in "banks" (to borrow terminology from CPU
   caches), and algorithms such as eviction buffer search only affect
   one specific bank.  This forestalls the problem that linear searching
   for a specific buffer across the whole cache takes too long: we only
   have to search the specific bank, whose size is small.  This work is
   authored by Andrey Borodin.

2. Change the locking regime for the SLRU banks, so that each bank uses
   a separate LWLock.  This allows for increased scalability.  This work
   is authored by Dilip Kumar.  (A part of this was previously committed as
   d172b717c6f4.)

Special care is taken so that the algorithms that can potentially
traverse more than one bank release one bank's lock before acquiring the
next.  This should happen rarely, but particularly clog.c's group commit
feature needed code adjustment to cope with this.  I (Álvaro) also added
lots of comments to make sure the design is sound.

The new GUCs match the names introduced by bcdfa5f2e2f2 in the
pg_stat_slru view.

The default values for these parameters are similar to the previous
sizes of each SLRU.  commit_ts, clog and subtrans accept value 0, which
means to adjust by dividing shared_buffers by 512 (so 2MB for every 1GB
of shared_buffers), with a cap of 8MB.  (A new slru.c function
SimpleLruAutotuneBuffers() was added to support this.)  The cap was
previously 1MB for clog, so for sites with more than 512MB of shared
memory the total memory used increases, which is likely a good tradeoff.
However, other SLRUs (notably multixact ones) retain smaller sizes and
don't support a configured value of 0.  These values based on
shared_buffers may need to be revisited, but that's an easy change.

There was some resistance to adding these new GUCs: it would be better
to adjust to memory pressure automatically somehow, for example by
stealing memory from shared_buffers (where the caches can grow and
shrink naturally).  However, doing that seems to be a much larger
project and one which has made virtually no progress in several years,
and because this is such a pain point for so many users, here we take
the pragmatic approach.

Author: Andrey Borodin <[email protected]>
Author: Dilip Kumar <[email protected]>
Reviewed-by: Amul Sul, Gilles Darold, Anastasia Lubennikova,
        Ivan Lazarev, Robert Haas, Thomas Munro, Tomas Vondra,
        Yura Sokolov, Васильев Дмитрий (Dmitry Vasiliev).
Discussion: https://postgr.es/m/[email protected]
Discussion: https://postgr.es/m/CAFiTN-vzDvNz=ExGXz6gdyjtzGixKSqs0mKHMmaQ8sOSEFZ33A@mail.gmail.com

Branch
------
master

Details
-------
https://git.postgresql.org/pg/commitdiff/53c2a97a92665be6bd7d70bd62ae6158fe4db96e

Modified Files
--------------
doc/src/sgml/config.sgml                        | 139 +++++++++
doc/src/sgml/monitoring.sgml                    |   9 +-
src/backend/access/transam/clog.c               | 243 +++++++++++-----
src/backend/access/transam/commit_ts.c          |  88 ++++--
src/backend/access/transam/multixact.c          | 190 +++++++++----
src/backend/access/transam/slru.c               | 357 +++++++++++++++++-------
src/backend/access/transam/subtrans.c           | 110 ++++++--
src/backend/commands/async.c                    |  61 ++--
src/backend/storage/lmgr/lwlock.c               |   9 +-
src/backend/storage/lmgr/lwlocknames.txt        |  14 +-
src/backend/storage/lmgr/predicate.c            |  34 ++-
src/backend/utils/activity/wait_event_names.txt |  15 +-
src/backend/utils/init/globals.c                |   9 +
src/backend/utils/misc/guc_tables.c             |  78 ++++++
src/backend/utils/misc/postgresql.conf.sample   |   9 +
src/include/access/clog.h                       |   1 -
src/include/access/commit_ts.h                  |   1 -
src/include/access/multixact.h                  |   4 -
src/include/access/slru.h                       |  86 ++++--
src/include/access/subtrans.h                   |   3 -
src/include/commands/async.h                    |   5 -
src/include/miscadmin.h                         |   8 +
src/include/storage/lwlock.h                    |   7 +
src/include/storage/predicate.h                 |   4 -
src/include/utils/guc_hooks.h                   |  11 +
src/test/modules/test_slru/test_slru.c          |  35 +--
26 files changed, 1177 insertions(+), 353 deletions(-)



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* Re: pgsql: Improve performance of subsystems on top of SLRU
@ 2024-03-03 14:29  Alvaro Herrera <[email protected]>
  parent: Alvaro Herrera <[email protected]>
  0 siblings, 1 reply; 51+ messages in thread

From: Alvaro Herrera @ 2024-03-03 14:29 UTC (permalink / raw)
  To: [email protected]; +Cc: Dilip Kumar <[email protected]>

On 2024-Feb-28, Alvaro Herrera wrote:

> Improve performance of subsystems on top of SLRU

Coverity had the following complaint about this commit:

________________________________________________________________________________________________________
*** CID NNNNNNN:  Control flow issues  (DEADCODE)
/srv/coverity/git/pgsql-git/postgresql/src/backend/access/transam/multixact.c: 1375 in GetMultiXactIdMembers()
1369             * and acquire the lock of the new bank.
1370             */
1371            lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
1372            if (lock != prevlock)
1373            {
1374                    if (prevlock != NULL)
>>>     CID 1592913:  Control flow issues  (DEADCODE)                                                                             
>>>     Execution cannot reach this statement: "LWLockRelease(prevlock);".                                                        
1375                            LWLockRelease(prevlock);
1376                    LWLockAcquire(lock, LW_EXCLUSIVE);
1377                    prevlock = lock;
1378            }
1379
1380            slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);

And I think it's correct that this is somewhat bogus, or at least
confusing: the only way to have control back here on line 1371 after
having executed once is via the "goto retry" line below; and there we
release "prevlock" and set it to NULL beforehand, so it's impossible for
prevlock to be NULL.  Looking closer I think this code is all confused,
so I suggest to rework it as shown in the attached patch.

I'll have a look at the other places where we use this "prevlock" coding
pattern tomorrow.

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


Attachments:

  [text/x-diff] 0001-rework-locking-code-in-GetMultiXactIdMembers.patch (3.9K, ../../[email protected]/2-0001-rework-locking-code-in-GetMultiXactIdMembers.patch)
  download | inline diff:
From a82fa380c7ff5a468ca920f4c06e626946bc8ecf Mon Sep 17 00:00:00 2001
From: Alvaro Herrera <[email protected]>
Date: Sun, 3 Mar 2024 15:20:36 +0100
Subject: [PATCH] rework locking code in GetMultiXactIdMembers

Per Coverity
---
 src/backend/access/transam/multixact.c | 52 ++++++++++----------------
 1 file changed, 20 insertions(+), 32 deletions(-)

diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 9b81506145..ec446949a9 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1250,14 +1250,12 @@ GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members,
 	MultiXactOffset offset;
 	int			length;
 	int			truelength;
-	int			i;
 	MultiXactId oldestMXact;
 	MultiXactId nextMXact;
 	MultiXactId tmpMXact;
 	MultiXactOffset nextOffset;
 	MultiXactMember *ptr;
 	LWLock	   *lock;
-	LWLock	   *prevlock = NULL;
 
 	debug_elog3(DEBUG2, "GetMembers: asked for %u", multi);
 
@@ -1364,18 +1362,9 @@ retry:
 	pageno = MultiXactIdToOffsetPage(multi);
 	entryno = MultiXactIdToOffsetEntry(multi);
 
-	/*
-	 * If this page falls under a different bank, release the old bank's lock
-	 * and acquire the lock of the new bank.
-	 */
+	/* Acquire the bank lock for the page we need. */
 	lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
-	if (lock != prevlock)
-	{
-		if (prevlock != NULL)
-			LWLockRelease(prevlock);
-		LWLockAcquire(lock, LW_EXCLUSIVE);
-		prevlock = lock;
-	}
+	LWLockAcquire(lock, LW_EXCLUSIVE);
 
 	slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
 	offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
@@ -1410,17 +1399,19 @@ retry:
 
 		if (pageno != prev_pageno)
 		{
+			LWLock	   *newlock;
+
 			/*
 			 * Since we're going to access a different SLRU page, if this page
 			 * falls under a different bank, release the old bank's lock and
 			 * acquire the lock of the new bank.
 			 */
-			lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
-			if (prevlock != lock)
+			newlock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
+			if (newlock != lock)
 			{
-				LWLockRelease(prevlock);
-				LWLockAcquire(lock, LW_EXCLUSIVE);
-				prevlock = lock;
+				LWLockRelease(lock);
+				LWLockAcquire(newlock, LW_EXCLUSIVE);
+				lock = newlock;
 			}
 			slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, tmpMXact);
 		}
@@ -1432,8 +1423,8 @@ retry:
 		if (nextMXOffset == 0)
 		{
 			/* Corner case 2: next multixact is still being filled in */
-			LWLockRelease(prevlock);
-			prevlock = NULL;
+			LWLockRelease(lock);
+			lock = NULL;
 			CHECK_FOR_INTERRUPTS();
 			pg_usleep(1000L);
 			goto retry;
@@ -1442,14 +1433,11 @@ retry:
 		length = nextMXOffset - offset;
 	}
 
-	LWLockRelease(prevlock);
-	prevlock = NULL;
-
 	ptr = (MultiXactMember *) palloc(length * sizeof(MultiXactMember));
 
 	truelength = 0;
 	prev_pageno = -1;
-	for (i = 0; i < length; i++, offset++)
+	for (int i = 0; i < length; i++, offset++)
 	{
 		TransactionId *xactptr;
 		uint32	   *flagsptr;
@@ -1462,18 +1450,19 @@ retry:
 
 		if (pageno != prev_pageno)
 		{
+			LWLock	   *newlock;
+
 			/*
 			 * Since we're going to access a different SLRU page, if this page
 			 * falls under a different bank, release the old bank's lock and
 			 * acquire the lock of the new bank.
 			 */
-			lock = SimpleLruGetBankLock(MultiXactMemberCtl, pageno);
-			if (lock != prevlock)
+			newlock = SimpleLruGetBankLock(MultiXactMemberCtl, pageno);
+			if (newlock != lock)
 			{
-				if (prevlock)
-					LWLockRelease(prevlock);
-				LWLockAcquire(lock, LW_EXCLUSIVE);
-				prevlock = lock;
+				LWLockRelease(lock);
+				LWLockAcquire(newlock, LW_EXCLUSIVE);
+				lock = newlock;
 			}
 
 			slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi);
@@ -1499,8 +1488,7 @@ retry:
 		truelength++;
 	}
 
-	if (prevlock)
-		LWLockRelease(prevlock);
+	LWLockRelease(lock);
 
 	/* A multixid with zero members should not happen */
 	Assert(truelength > 0);
-- 
2.39.2



^ permalink  raw  reply  [nested|flat] 51+ messages in thread

* Re: pgsql: Improve performance of subsystems on top of SLRU
@ 2024-03-04 06:14  Dilip Kumar <[email protected]>
  parent: Alvaro Herrera <[email protected]>
  0 siblings, 0 replies; 51+ messages in thread

From: Dilip Kumar @ 2024-03-04 06:14 UTC (permalink / raw)
  To: Alvaro Herrera <[email protected]>; +Cc: [email protected]

On Mon, Mar 4, 2024 at 1:56 AM Alvaro Herrera <[email protected]> wrote:
>
> On 2024-Feb-28, Alvaro Herrera wrote:
>
> > Improve performance of subsystems on top of SLRU
>
> Coverity had the following complaint about this commit:
>
> ________________________________________________________________________________________________________
> *** CID NNNNNNN:  Control flow issues  (DEADCODE)
> /srv/coverity/git/pgsql-git/postgresql/src/backend/access/transam/multixact.c: 1375 in GetMultiXactIdMembers()
> 1369             * and acquire the lock of the new bank.
> 1370             */
> 1371            lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
> 1372            if (lock != prevlock)
> 1373            {
> 1374                    if (prevlock != NULL)
> >>>     CID 1592913:  Control flow issues  (DEADCODE)
> >>>     Execution cannot reach this statement: "LWLockRelease(prevlock);".
> 1375                            LWLockRelease(prevlock);
> 1376                    LWLockAcquire(lock, LW_EXCLUSIVE);
> 1377                    prevlock = lock;
> 1378            }
> 1379
> 1380            slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
>
> And I think it's correct that this is somewhat bogus, or at least
> confusing: the only way to have control back here on line 1371 after
> having executed once is via the "goto retry" line below; and there we
> release "prevlock" and set it to NULL beforehand, so it's impossible for
> prevlock to be NULL.  Looking closer I think this code is all confused,
> so I suggest to rework it as shown in the attached patch.
>
> I'll have a look at the other places where we use this "prevlock" coding
> pattern tomorrow.


+ /* Acquire the bank lock for the page we need. */
  lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
- if (lock != prevlock)
- {
- if (prevlock != NULL)
- LWLockRelease(prevlock);
- LWLockAcquire(lock, LW_EXCLUSIVE);
- prevlock = lock;
- }
+ LWLockAcquire(lock, LW_EXCLUSIVE);

This part is definitely an improvement.

I am not sure about the other changes, I mean that makes the code much
simpler but now we are not releasing the 'MultiXactOffsetCtl' related
bank lock, and later in the following loop, we are comparing that lock
against 'MultiXactMemberCtl' related bank lock. This makes code
simpler because now in the loop we are sure that we are always holding
the lock but I do not like comparing the bank locks for 2 different
SLRUs, although there is no problem as there would not be a common
lock address, anyway, I do not have any strong objection to what you
have done here.

-- 
Regards,
Dilip Kumar
EnterpriseDB: http://www.enterprisedb.com






^ permalink  raw  reply  [nested|flat] 51+ messages in thread


end of thread, other threads:[~2024-03-04 06:14 UTC | newest]

Thread overview: 51+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2021-03-04 08:00 [PATCH 1/8] Get datum from tuple which doesn't contain external data Dilip Kumar <[email protected]>
2024-02-28 16:07 pgsql: Improve performance of subsystems on top of SLRU Alvaro Herrera <[email protected]>
2024-03-03 14:29 ` Re: pgsql: Improve performance of subsystems on top of SLRU Alvaro Herrera <[email protected]>
2024-03-04 06:14   ` Re: pgsql: Improve performance of subsystems on top of SLRU Dilip Kumar <[email protected]>

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox