From 7783e62baba6d3b0b4b2df1086275bfcc8969a31 Mon Sep 17 00:00:00 2001
From: Dean Rasheed <dean.a.rasheed@gmail.com>
Date: Thu, 10 Jul 2025 13:51:53 +0100
Subject: [PATCH v5 1/5] Convert src/tools/testint128.c into a test module.

This creates a new test module "test_int128" and moves
src/tools/testint128.c to src/test/modules/test_int128/test_int128.c,
so that it can be built using the normal build system, and 128-bit
integer arithmetic gets tested automatically.

While at it, fix the test128 union in the test code: the "hl" member
of test128 was incorrectly defined to be a union instead of a struct,
which meant that the tests were only ever setting and checking half of
each 128-bit integer value.
---
 src/include/common/int128.h                   |  2 +-
 src/test/modules/Makefile                     |  1 +
 src/test/modules/meson.build                  |  1 +
 src/test/modules/test_int128/.gitignore       |  2 +
 src/test/modules/test_int128/Makefile         | 23 ++++++++
 src/test/modules/test_int128/meson.build      | 33 ++++++++++++
 .../modules/test_int128/t/001_test_int128.pl  | 27 ++++++++++
 .../modules/test_int128/test_int128.c}        | 54 +++++++++++++------
 8 files changed, 125 insertions(+), 18 deletions(-)
 create mode 100644 src/test/modules/test_int128/.gitignore
 create mode 100644 src/test/modules/test_int128/Makefile
 create mode 100644 src/test/modules/test_int128/meson.build
 create mode 100644 src/test/modules/test_int128/t/001_test_int128.pl
 rename src/{tools/testint128.c => test/modules/test_int128/test_int128.c} (69%)

diff --git a/src/include/common/int128.h b/src/include/common/int128.h
index a50f5709c29..f22530a164e 100644
--- a/src/include/common/int128.h
+++ b/src/include/common/int128.h
@@ -6,7 +6,7 @@
  * We make use of the native int128 type if there is one, otherwise
  * implement things the hard way based on two int64 halves.
  *
- * See src/tools/testint128.c for a simple test harness for this file.
+ * See src/test/modules/test_int128 for a simple test harness for this file.
  *
  * Copyright (c) 2017-2025, PostgreSQL Global Development Group
  *
diff --git a/src/test/modules/Makefile b/src/test/modules/Makefile
index aa1d27bbed3..a31fad53497 100644
--- a/src/test/modules/Makefile
+++ b/src/test/modules/Makefile
@@ -24,6 +24,7 @@ SUBDIRS = \
 		  test_escape \
 		  test_extensions \
 		  test_ginpostinglist \
+		  test_int128 \
 		  test_integerset \
 		  test_json_parser \
 		  test_lfind \
diff --git a/src/test/modules/meson.build b/src/test/modules/meson.build
index 9de0057bd1d..df4f13fcbb0 100644
--- a/src/test/modules/meson.build
+++ b/src/test/modules/meson.build
@@ -23,6 +23,7 @@ subdir('test_dsm_registry')
 subdir('test_escape')
 subdir('test_extensions')
 subdir('test_ginpostinglist')
+subdir('test_int128')
 subdir('test_integerset')
 subdir('test_json_parser')
 subdir('test_lfind')
diff --git a/src/test/modules/test_int128/.gitignore b/src/test/modules/test_int128/.gitignore
new file mode 100644
index 00000000000..277fec6ed2c
--- /dev/null
+++ b/src/test/modules/test_int128/.gitignore
@@ -0,0 +1,2 @@
+/tmp_check/
+/test_int128
diff --git a/src/test/modules/test_int128/Makefile b/src/test/modules/test_int128/Makefile
new file mode 100644
index 00000000000..2e86ee93a9d
--- /dev/null
+++ b/src/test/modules/test_int128/Makefile
@@ -0,0 +1,23 @@
+# src/test/modules/test_int128/Makefile
+
+PGFILEDESC = "test_int128 - test 128-bit integer arithmetic"
+
+PROGRAM = test_int128
+OBJS = $(WIN32RES) test_int128.o
+
+PG_CPPFLAGS = -I$(libpq_srcdir)
+PG_LIBS_INTERNAL += $(libpq_pgport)
+
+NO_INSTALL = 1
+TAP_TESTS = 1
+
+ifdef USE_PGXS
+PG_CONFIG = pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+else
+subdir = src/test/modules/test_int128
+top_builddir = ../../../..
+include $(top_builddir)/src/Makefile.global
+include $(top_srcdir)/contrib/contrib-global.mk
+endif
diff --git a/src/test/modules/test_int128/meson.build b/src/test/modules/test_int128/meson.build
new file mode 100644
index 00000000000..4c2be7a0326
--- /dev/null
+++ b/src/test/modules/test_int128/meson.build
@@ -0,0 +1,33 @@
+# Copyright (c) 2025, PostgreSQL Global Development Group
+
+test_int128_sources = files(
+  'test_int128.c',
+)
+
+if host_system == 'windows'
+  test_int128_sources += rc_bin_gen.process(win32ver_rc, extra_args: [
+    '--NAME', 'test_int128',
+    '--FILEDESC', 'test int128 program',])
+endif
+
+test_int128 = executable('test_int128',
+  test_int128_sources,
+  dependencies: [frontend_code, libpq],
+  kwargs: default_bin_args + {
+    'install': false,
+  },
+)
+testprep_targets += test_int128
+
+
+tests += {
+  'name': 'test_int128',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'tests': [
+      't/001_test_int128.pl',
+    ],
+    'deps': [test_int128],
+  },
+}
diff --git a/src/test/modules/test_int128/t/001_test_int128.pl b/src/test/modules/test_int128/t/001_test_int128.pl
new file mode 100644
index 00000000000..0c683869f34
--- /dev/null
+++ b/src/test/modules/test_int128/t/001_test_int128.pl
@@ -0,0 +1,27 @@
+# Copyright (c) 2025, PostgreSQL Global Development Group
+
+# Test 128-bit integer arithmetic code in int128.h
+
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Utils;
+use Test::More;
+
+# Run the test program with 1M iterations
+my $exe = "test_int128";
+my $size = 1_000_000;
+
+note "testing executable $exe";
+
+my ($stdout, $stderr) = run_command([ $exe, $size ]);
+
+SKIP:
+{
+	skip "no native int128 type", 2 if $stdout =~ /skipping tests/;
+
+	is($stdout, "", "test_int128: no stdout");
+	is($stderr, "", "test_int128: no stderr");
+}
+
+done_testing();
diff --git a/src/tools/testint128.c b/src/test/modules/test_int128/test_int128.c
similarity index 69%
rename from src/tools/testint128.c
rename to src/test/modules/test_int128/test_int128.c
index a25631e277d..8a96a4bff83 100644
--- a/src/tools/testint128.c
+++ b/src/test/modules/test_int128/test_int128.c
@@ -1,6 +1,6 @@
 /*-------------------------------------------------------------------------
  *
- * testint128.c
+ * test_int128.c
  *	  Testbed for roll-our-own 128-bit integer arithmetic.
  *
  * This is a standalone test program that compares the behavior of an
@@ -10,13 +10,18 @@
  *
  *
  * IDENTIFICATION
- *	  src/tools/testint128.c
+ *	  src/test/modules/test_int128/test_int128.c
  *
  *-------------------------------------------------------------------------
  */
 
 #include "postgres_fe.h"
 
+#include <time.h>
+
+/* Require a native int128 type */
+#ifdef HAVE_INT128
+
 /*
  * By default, we test the non-native implementation in int128.h; but
  * by predefining USE_NATIVE_INT128 to 1, you can test the native
@@ -36,7 +41,7 @@ typedef union
 {
 	int128		i128;
 	INT128		I128;
-	union
+	struct
 	{
 #ifdef WORDS_BIGENDIAN
 		int64		hi;
@@ -48,6 +53,7 @@ typedef union
 	}			hl;
 }			test128;
 
+#define INT128_HEX_FORMAT	"%016" PRIx64 "%016" PRIx64
 
 /*
  * Control version of comparator.
@@ -75,7 +81,7 @@ main(int argc, char **argv)
 {
 	long		count;
 
-	pg_prng_seed(&pg_global_prng_state, 0);
+	pg_prng_seed(&pg_global_prng_state, (uint64) time(NULL));
 
 	if (argc >= 2)
 		count = strtol(argv[1], NULL, 0);
@@ -99,9 +105,9 @@ main(int argc, char **argv)
 
 		if (t1.hl.hi != t2.hl.hi || t1.hl.lo != t2.hl.lo)
 		{
-			printf("%016lX%016lX + unsigned %lX\n", x, y, z);
-			printf("native = %016lX%016lX\n", t1.hl.hi, t1.hl.lo);
-			printf("result = %016lX%016lX\n", t2.hl.hi, t2.hl.lo);
+			printf(INT128_HEX_FORMAT " + unsigned " INT64_HEX_FORMAT "\n", x, y, z);
+			printf("native = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
+			printf("result = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
 			return 1;
 		}
 
@@ -114,9 +120,9 @@ main(int argc, char **argv)
 
 		if (t1.hl.hi != t2.hl.hi || t1.hl.lo != t2.hl.lo)
 		{
-			printf("%016lX%016lX + signed %lX\n", x, y, z);
-			printf("native = %016lX%016lX\n", t1.hl.hi, t1.hl.lo);
-			printf("result = %016lX%016lX\n", t2.hl.hi, t2.hl.lo);
+			printf(INT128_HEX_FORMAT " + signed " INT64_HEX_FORMAT "\n", x, y, z);
+			printf("native = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
+			printf("result = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
 			return 1;
 		}
 
@@ -128,9 +134,9 @@ main(int argc, char **argv)
 
 		if (t1.hl.hi != t2.hl.hi || t1.hl.lo != t2.hl.lo)
 		{
-			printf("%lX * %lX\n", x, y);
-			printf("native = %016lX%016lX\n", t1.hl.hi, t1.hl.lo);
-			printf("result = %016lX%016lX\n", t2.hl.hi, t2.hl.lo);
+			printf(INT64_HEX_FORMAT " * " INT64_HEX_FORMAT "\n", x, y);
+			printf("native = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
+			printf("result = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
 			return 1;
 		}
 
@@ -146,8 +152,8 @@ main(int argc, char **argv)
 			printf("comparison failure: %d vs %d\n",
 				   my_int128_compare(t1.i128, t2.i128),
 				   int128_compare(t1.I128, t2.I128));
-			printf("arg1 = %016lX%016lX\n", t1.hl.hi, t1.hl.lo);
-			printf("arg2 = %016lX%016lX\n", t2.hl.hi, t2.hl.lo);
+			printf("arg1 = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
+			printf("arg2 = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
 			return 1;
 		}
 
@@ -160,11 +166,25 @@ main(int argc, char **argv)
 			printf("comparison failure: %d vs %d\n",
 				   my_int128_compare(t1.i128, t2.i128),
 				   int128_compare(t1.I128, t2.I128));
-			printf("arg1 = %016lX%016lX\n", t1.hl.hi, t1.hl.lo);
-			printf("arg2 = %016lX%016lX\n", t2.hl.hi, t2.hl.lo);
+			printf("arg1 = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
+			printf("arg2 = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
 			return 1;
 		}
 	}
 
 	return 0;
 }
+
+#else							/* ! HAVE_INT128 */
+
+/*
+ * For now, do nothing if we don't have a native int128 type.
+ */
+int
+main(int argc, char **argv)
+{
+	printf("skipping tests: no native int128 type\n");
+	return 0;
+}
+
+#endif
-- 
2.43.0

