From 968caa8cdd45252ec9f507dde3bff403f937cd21 Mon Sep 17 00:00:00 2001
From: Daniel Gustafsson <dgustafsson@postgresql.org>
Date: Sun, 5 Apr 2026 00:01:06 +0200
Subject: [PATCH 2/2] Refactor checksum injection point tests

Refactor the injection point tests for online checksum enabling to
use the injection_points extension.

Author: Daniel Gustafsson <daniel@yesql.se>
---
 src/backend/postmaster/datachecksum_state.c   | 26 +++++-
 .../modules/test_checksums/t/005_injection.pl |  7 +-
 .../test_checksums/t/006_pgbench_single.pl    | 13 ++-
 .../test_checksums/t/007_pgbench_standby.pl   | 14 +++-
 .../test_checksums/test_checksums--1.0.sql    |  8 --
 .../modules/test_checksums/test_checksums.c   | 79 -------------------
 6 files changed, 48 insertions(+), 99 deletions(-)

diff --git a/src/backend/postmaster/datachecksum_state.c b/src/backend/postmaster/datachecksum_state.c
index 76004bcedc6..48326345dde 100644
--- a/src/backend/postmaster/datachecksum_state.c
+++ b/src/backend/postmaster/datachecksum_state.c
@@ -1197,8 +1197,15 @@ ProcessAllDatabases(void)
 
 		result = ProcessDatabase(db);
 
+#ifdef USE_INJECTION_POINTS
 		/* Allow a test process to alter the result of the operation */
-		INJECTION_POINT("datachecksumsworker-modify-db-result", &result);
+		if (IS_INJECTION_POINT_ATTACHED("datachecksumsworker-fail-db-result"))
+		{
+			result = DATACHECKSUMSWORKER_FAILED;
+			INJECTION_POINT_CACHED("datachecksumsworker-fail-db-result",
+								   db->dbname);
+		}
+#endif
 
 		pgstat_progress_update_param(PROGRESS_DATACHECKSUMS_DBS_DONE,
 									 ++cumulative_total);
@@ -1451,6 +1458,9 @@ DataChecksumsWorkerMain(Datum arg)
 	BufferAccessStrategy strategy;
 	bool		aborted = false;
 	int64		rels_done;
+#ifdef USE_INJECTION_POINTS
+	bool		retried = false;
+#endif
 
 	operation = ENABLE_DATACHECKSUMS;
 
@@ -1566,7 +1576,19 @@ DataChecksumsWorkerMain(Datum arg)
 		}
 		list_free(CurrentTempTables);
 
-		INJECTION_POINT("datachecksumsworker-fake-temptable-wait", &numleft);
+#ifdef USE_INJECTION_POINTS
+		if (IS_INJECTION_POINT_ATTACHED("datachecksumsworker-fake-temptable-wait"))
+		{
+			/* Make sure to just cause one retry */
+			if (!retried && numleft == 0)
+			{
+				numleft = 1;
+				retried = true;
+
+				INJECTION_POINT_CACHED("datachecksumsworker-fake-temptable-wait", NULL);
+			}
+		}
+#endif
 
 		if (numleft == 0)
 			break;
diff --git a/src/test/modules/test_checksums/t/005_injection.pl b/src/test/modules/test_checksums/t/005_injection.pl
index 897f282a1f2..ff383cf6b9d 100644
--- a/src/test/modules/test_checksums/t/005_injection.pl
+++ b/src/test/modules/test_checksums/t/005_injection.pl
@@ -32,6 +32,7 @@ $node->start;
 
 # Set up test environment
 $node->safe_psql('postgres', 'CREATE EXTENSION test_checksums;');
+$node->safe_psql('postgres', 'CREATE EXTENSION injection_points;');
 
 # ---------------------------------------------------------------------------
 # Inducing failures and crashes in processing
@@ -39,9 +40,9 @@ $node->safe_psql('postgres', 'CREATE EXTENSION test_checksums;');
 # Force enabling checksums to fail by marking one of the databases as having
 # failed in processing.
 disable_data_checksums($node, wait => 1);
-$node->safe_psql('postgres', 'SELECT dcw_inject_fail_database(true);');
+$node->safe_psql('postgres', "SELECT injection_points_attach('datachecksumsworker-fail-db-result','notice');");
 enable_data_checksums($node, wait => 'off');
-$node->safe_psql('postgres', 'SELECT dcw_inject_fail_database(false);');
+$node->safe_psql('postgres', "SELECT injection_points_detach('datachecksumsworker-fail-db-result');");
 
 # Make sure that disabling after a failure works
 disable_data_checksums($node);
@@ -66,7 +67,7 @@ SKIP:
 	# will force the processing to wait and retry in order to wait for it to
 	# disappear.
 	disable_data_checksums($node, wait => 1);
-	$node->safe_psql('postgres', 'SELECT dcw_fake_temptable(true);');
+	$node->safe_psql('postgres', "SELECT injection_points_attach('datachecksumsworker-fake-temptable-wait', 'notice');");
 	enable_data_checksums($node, wait => 'on');
 }
 
diff --git a/src/test/modules/test_checksums/t/006_pgbench_single.pl b/src/test/modules/test_checksums/t/006_pgbench_single.pl
index 0ab5b04b931..f83b39247ae 100644
--- a/src/test/modules/test_checksums/t/006_pgbench_single.pl
+++ b/src/test/modules/test_checksums/t/006_pgbench_single.pl
@@ -89,14 +89,19 @@ sub background_rw_pgbench
 # before and after state.
 sub flip_data_checksums
 {
+	my $temptablewait = 0;
+
 	# First, make sure the cluster is in the state we expect it to be
 	test_checksum_state($node, $data_checksum_state);
 
 	if ($data_checksum_state eq 'off')
 	{
 		# Coin-toss to see if we are injecting a retry due to a temptable
-		$node->safe_psql('postgres', 'SELECT dcw_fake_temptable();')
-		  if cointoss();
+		if (cointoss())
+		{
+			$node->safe_psql('postgres', "SELECT injection_points_attach('datachecksumsworker-fake-temptable-wait', 'notice');");
+			$temptablewait = 1;
+		}
 
 		# log LSN right before we start changing checksums
 		my $result =
@@ -117,7 +122,8 @@ sub flip_data_checksums
 
 		random_sleep() if ($extended);
 
-		$node->safe_psql('postgres', 'SELECT dcw_fake_temptable(false);');
+		$node->safe_psql('postgres', "SELECT injection_points_detach('datachecksumsworker-fake-temptable-wait');")
+			if ($temptablewait);
 		$data_checksum_state = 'on';
 	}
 	elsif ($data_checksum_state eq 'on')
@@ -165,6 +171,7 @@ log_statement = none
 ]);
 $node->start;
 $node->safe_psql('postgres', 'CREATE EXTENSION test_checksums;');
+$node->safe_psql('postgres', 'CREATE EXTENSION injection_points;');
 # Create some content to have un-checksummed data in the cluster
 $node->safe_psql('postgres',
 	"CREATE TABLE t AS SELECT generate_series(1, 100000) AS a;");
diff --git a/src/test/modules/test_checksums/t/007_pgbench_standby.pl b/src/test/modules/test_checksums/t/007_pgbench_standby.pl
index b0d40d24005..1cc95916dda 100644
--- a/src/test/modules/test_checksums/t/007_pgbench_standby.pl
+++ b/src/test/modules/test_checksums/t/007_pgbench_standby.pl
@@ -99,6 +99,8 @@ sub background_pgbench
 # before and after state.
 sub flip_data_checksums
 {
+	my $temptablewait = 0;
+
 	# First, make sure the cluster is in the state we expect it to be
 	test_checksum_state($node_primary, $data_checksum_state);
 	test_checksum_state($node_standby, $data_checksum_state);
@@ -106,8 +108,11 @@ sub flip_data_checksums
 	if ($data_checksum_state eq 'off')
 	{
 		# Coin-toss to see if we are injecting a retry due to a temptable
-		$node_primary->safe_psql('postgres', 'SELECT dcw_fake_temptable();')
-		  if cointoss();
+		if (cointoss())
+		{
+			$node_primary->safe_psql('postgres', "SELECT injection_points_attach('datachecksumsworker-fake-temptable-wait', 'notice');");
+			$temptablewait = 1;
+		}
 
 		# log LSN right before we start changing checksums
 		my $result =
@@ -153,8 +158,8 @@ sub flip_data_checksums
 		random_sleep() if ($extended);
 		wait_for_checksum_state($node_standby, 'on');
 
-		$node_primary->safe_psql('postgres',
-			'SELECT dcw_fake_temptable(false);');
+		$node_primary->safe_psql('postgres', "SELECT injection_points_detach('datachecksumsworker-fake-temptable-wait');")
+			if ($temptablewait);
 		$data_checksum_state = 'on';
 	}
 	elsif ($data_checksum_state eq 'on')
@@ -207,6 +212,7 @@ log_statement = none
 ]);
 $node_primary->start;
 $node_primary->safe_psql('postgres', 'CREATE EXTENSION test_checksums;');
+$node_primary->safe_psql('postgres', 'CREATE EXTENSION injection_points;');
 # Create some content to have un-checksummed data in the cluster
 $node_primary->safe_psql('postgres',
 	"CREATE TABLE t AS SELECT generate_series(1, 100000) AS a;");
diff --git a/src/test/modules/test_checksums/test_checksums--1.0.sql b/src/test/modules/test_checksums/test_checksums--1.0.sql
index 90642d247fa..c674fee02bb 100644
--- a/src/test/modules/test_checksums/test_checksums--1.0.sql
+++ b/src/test/modules/test_checksums/test_checksums--1.0.sql
@@ -14,11 +14,3 @@ CREATE FUNCTION dcw_inject_launcher_delay(attach boolean DEFAULT true)
 CREATE FUNCTION dcw_inject_startup_delay(attach boolean DEFAULT true)
 	RETURNS pg_catalog.void
 	AS 'MODULE_PATHNAME' LANGUAGE C;
-
-CREATE FUNCTION dcw_inject_fail_database(attach boolean DEFAULT true)
-	RETURNS pg_catalog.void
-	AS 'MODULE_PATHNAME' LANGUAGE C;
-
-CREATE FUNCTION dcw_fake_temptable(attach boolean DEFAULT true)
-	RETURNS pg_catalog.void
-	AS 'MODULE_PATHNAME' LANGUAGE C;
diff --git a/src/test/modules/test_checksums/test_checksums.c b/src/test/modules/test_checksums/test_checksums.c
index e2b91f9c78c..c2eabc2821c 100644
--- a/src/test/modules/test_checksums/test_checksums.c
+++ b/src/test/modules/test_checksums/test_checksums.c
@@ -25,8 +25,6 @@ extern PGDLLEXPORT void dc_delay_barrier(const char *name, const void *private_d
 extern PGDLLEXPORT void dc_modify_db_result(const char *name, const void *private_data, void *arg);
 extern PGDLLEXPORT void dc_fake_temptable(const char *name, const void *private_data, void *arg);
 
-extern PGDLLEXPORT void crash(const char *name, const void *private_data, void *arg);
-
 /*
  * Test for delaying emission of procsignalbarriers.
  */
@@ -107,80 +105,3 @@ dcw_inject_startup_delay(PG_FUNCTION_ARGS)
 #endif
 	PG_RETURN_VOID();
 }
-
-#ifdef USE_INJECTION_POINTS
-static uint32 db_fail = DATACHECKSUMSWORKER_FAILED;
-#endif
-
-void
-dc_modify_db_result(const char *name, const void *private_data, void *arg)
-{
-	DataChecksumsWorkerResult *res = (DataChecksumsWorkerResult *) arg;
-	uint32		new_res = *(uint32 *) private_data;
-
-	*res = new_res;
-}
-
-PG_FUNCTION_INFO_V1(dcw_inject_fail_database);
-Datum
-dcw_inject_fail_database(PG_FUNCTION_ARGS)
-{
-#ifdef USE_INJECTION_POINTS
-	bool		attach = PG_GETARG_BOOL(0);
-
-	if (attach)
-		InjectionPointAttach("datachecksumsworker-modify-db-result",
-							 "test_checksums",
-							 "dc_modify_db_result",
-							 &db_fail,
-							 sizeof(uint32));
-	else
-		InjectionPointDetach("datachecksumsworker-modify-db-result");
-#else
-	elog(ERROR,
-		 "test is not working as intended when injection points are disabled");
-#endif
-	PG_RETURN_VOID();
-}
-
-/*
- * Test to force waiting for existing temptables.
- */
-void
-dc_fake_temptable(const char *name, const void *private_data, void *arg)
-{
-	static bool first_pass = true;
-	int		   *numleft = (int *) arg;
-
-	if (first_pass)
-		*numleft = 1;
-	first_pass = false;
-}
-
-PG_FUNCTION_INFO_V1(dcw_fake_temptable);
-Datum
-dcw_fake_temptable(PG_FUNCTION_ARGS)
-{
-#ifdef USE_INJECTION_POINTS
-	bool		attach = PG_GETARG_BOOL(0);
-
-	if (attach)
-		InjectionPointAttach("datachecksumsworker-fake-temptable-wait",
-							 "test_checksums",
-							 "dc_fake_temptable",
-							 NULL,
-							 0);
-	else
-		InjectionPointDetach("datachecksumsworker-fake-temptable-wait");
-#else
-	elog(ERROR,
-		 "test is not working as intended when injection points are disabled");
-#endif
-	PG_RETURN_VOID();
-}
-
-void
-crash(const char *name, const void *private_data, void *arg)
-{
-	abort();
-}
-- 
2.39.3 (Apple Git-146)

