From 1adbdb01db2a0498d247fd2f3a860945a12ab228 Mon Sep 17 00:00:00 2001
From: Corey Huinker <corey.huinker@gmail.com>
Date: Mon, 4 Nov 2024 14:02:57 -0500
Subject: [PATCH v30 4/4] Enable in-place updates for
 pg_restore_relation_stats.

This matches the behavior of the ANALYZE command, and would avoid
bloating pg_class in an upgrade situation wherein
pg_restore_relation_stats would be called for nearly every relation in
the database.
---
 src/backend/statistics/relation_stats.c | 72 +++++++++++++++++++------
 1 file changed, 55 insertions(+), 17 deletions(-)

diff --git a/src/backend/statistics/relation_stats.c b/src/backend/statistics/relation_stats.c
index ed5dea2e05..939ad56fc2 100644
--- a/src/backend/statistics/relation_stats.c
+++ b/src/backend/statistics/relation_stats.c
@@ -22,6 +22,7 @@
 #include "statistics/stat_utils.h"
 #include "utils/fmgrprotos.h"
 #include "utils/syscache.h"
+#include "utils/fmgroids.h"
 
 #define DEFAULT_RELPAGES Int32GetDatum(0)
 #define DEFAULT_RELTUPLES Float4GetDatum(-1.0)
@@ -50,13 +51,14 @@ static struct StatsArgInfo relarginfo[] =
 	[NUM_RELATION_STATS_ARGS] = {0}
 };
 
-static bool relation_statistics_update(FunctionCallInfo fcinfo, int elevel);
+static bool relation_statistics_update(FunctionCallInfo fcinfo, int elevel,
+									   bool inplace);
 
 /*
  * Internal function for modifying statistics for a relation.
  */
 static bool
-relation_statistics_update(FunctionCallInfo fcinfo, int elevel)
+relation_statistics_update(FunctionCallInfo fcinfo, int elevel, bool inplace)
 {
 	Oid			reloid;
 	Relation	crel;
@@ -68,6 +70,7 @@ relation_statistics_update(FunctionCallInfo fcinfo, int elevel)
 	int			ncols = 0;
 	TupleDesc	tupdesc;
 	bool		result = true;
+	void	   *inplace_state;
 
 	stats_check_required_arg(fcinfo, relarginfo, RELATION_ARG);
 	reloid = PG_GETARG_OID(RELATION_ARG);
@@ -81,7 +84,20 @@ relation_statistics_update(FunctionCallInfo fcinfo, int elevel)
 	crel = table_open(RelationRelationId, RowExclusiveLock);
 
 	tupdesc = RelationGetDescr(crel);
-	ctup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(reloid));
+	if (inplace)
+	{
+		ScanKeyData key[1];
+
+		ctup = NULL;
+
+		ScanKeyInit(&key[0], Anum_pg_class_oid, BTEqualStrategyNumber, F_OIDEQ,
+					ObjectIdGetDatum(reloid));
+		systable_inplace_update_begin(crel, ClassOidIndexId, true, NULL, 1, key,
+									  &ctup, &inplace_state);
+	}
+	else
+		ctup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(reloid));
+
 	if (!HeapTupleIsValid(ctup))
 	{
 		ereport(elevel,
@@ -112,8 +128,13 @@ relation_statistics_update(FunctionCallInfo fcinfo, int elevel)
 		}
 		else if (relpages != pgcform->relpages)
 		{
-			replaces[ncols] = Anum_pg_class_relpages;
-			values[ncols] = Int32GetDatum(relpages);
+			if (inplace)
+				pgcform->relpages = relpages;
+			else
+			{
+				replaces[ncols] = Anum_pg_class_relpages;
+				values[ncols] = Int32GetDatum(relpages);
+			}
 			ncols++;
 		}
 	}
@@ -131,8 +152,13 @@ relation_statistics_update(FunctionCallInfo fcinfo, int elevel)
 		}
 		else if (reltuples != pgcform->reltuples)
 		{
-			replaces[ncols] = Anum_pg_class_reltuples;
-			values[ncols] = Float4GetDatum(reltuples);
+			if (inplace)
+				pgcform->reltuples = reltuples;
+			else
+			{
+				replaces[ncols] = Anum_pg_class_reltuples;
+				values[ncols] = Float4GetDatum(reltuples);
+			}
 			ncols++;
 		}
 
@@ -151,8 +177,13 @@ relation_statistics_update(FunctionCallInfo fcinfo, int elevel)
 		}
 		else if (relallvisible != pgcform->relallvisible)
 		{
-			replaces[ncols] = Anum_pg_class_relallvisible;
-			values[ncols] = Int32GetDatum(relallvisible);
+			if (inplace)
+				pgcform->relallvisible = relallvisible;
+			else
+			{
+				replaces[ncols] = Anum_pg_class_relallvisible;
+				values[ncols] = Int32GetDatum(relallvisible);
+			}
 			ncols++;
 		}
 	}
@@ -160,13 +191,20 @@ relation_statistics_update(FunctionCallInfo fcinfo, int elevel)
 	/* only update pg_class if there is a meaningful change */
 	if (ncols > 0)
 	{
-		HeapTuple	newtup;
+		if (inplace)
+			systable_inplace_update_finish(inplace_state, ctup);
+		else
+		{
+			HeapTuple	newtup;
 
-		newtup = heap_modify_tuple_by_cols(ctup, tupdesc, ncols, replaces, values,
-										   nulls);
-		CatalogTupleUpdate(crel, &newtup->t_self, newtup);
-		heap_freetuple(newtup);
+			newtup = heap_modify_tuple_by_cols(ctup, tupdesc, ncols, replaces, values,
+											nulls);
+			CatalogTupleUpdate(crel, &newtup->t_self, newtup);
+			heap_freetuple(newtup);
+		}
 	}
+	else if (inplace)
+		systable_inplace_update_cancel(inplace_state);
 
 	/* release the lock, consistent with vac_update_relstats() */
 	table_close(crel, RowExclusiveLock);
@@ -182,7 +220,7 @@ relation_statistics_update(FunctionCallInfo fcinfo, int elevel)
 Datum
 pg_set_relation_stats(PG_FUNCTION_ARGS)
 {
-	relation_statistics_update(fcinfo, ERROR);
+	relation_statistics_update(fcinfo, ERROR, false);
 	PG_RETURN_VOID();
 }
 
@@ -206,7 +244,7 @@ pg_clear_relation_stats(PG_FUNCTION_ARGS)
 	newfcinfo->args[3].value = DEFAULT_RELALLVISIBLE;
 	newfcinfo->args[3].isnull = false;
 
-	relation_statistics_update(newfcinfo, ERROR);
+	relation_statistics_update(newfcinfo, ERROR, false);
 	PG_RETURN_VOID();
 }
 
@@ -224,7 +262,7 @@ pg_restore_relation_stats(PG_FUNCTION_ARGS)
 										  relarginfo, WARNING))
 		result = false;
 
-	if (!relation_statistics_update(positional_fcinfo, WARNING))
+	if (!relation_statistics_update(positional_fcinfo, WARNING, true))
 		result = false;
 
 	PG_RETURN_BOOL(result);
-- 
2.47.0

