From 55ca2b6123cb4dd7820b39ae4ef3bacfb00df81c Mon Sep 17 00:00:00 2001
From: Tomas Vondra <tomas@vondra.me>
Date: Wed, 1 Oct 2025 01:34:12 +0200
Subject: [PATCH v20251001 22/25] experimental: zlib (gzip?) compression

---
 src/backend/storage/file/buffile.c  | 50 +++++++++++++++++++++++++++++
 src/backend/utils/misc/guc_tables.c |  3 ++
 src/include/storage/buffile.h       |  3 +-
 3 files changed, 55 insertions(+), 1 deletion(-)

diff --git a/src/backend/storage/file/buffile.c b/src/backend/storage/file/buffile.c
index e3d4e2a342e..380537fb126 100644
--- a/src/backend/storage/file/buffile.c
+++ b/src/backend/storage/file/buffile.c
@@ -60,10 +60,15 @@
 #include <lz4.h>
 #endif
 
+#ifdef HAVE_LIBZ
+#include <zlib.h>
+#endif
+
 /* Compression types */
 #define TEMP_NONE_COMPRESSION  0
 #define TEMP_PGLZ_COMPRESSION  1
 #define TEMP_LZ4_COMPRESSION   2
+#define TEMP_GZIP_COMPRESSION  3
 
 /*
  * We break BufFiles into gigabyte-sized segments, regardless of RELSEG_SIZE.
@@ -294,6 +299,15 @@ BufFileCreateCompressTemp(bool interXact)
 				size = LZ4_compressBound(BLCKSZ) + sizeof(CompressHeader);
 #endif
 				break;
+
+			case TEMP_GZIP_COMPRESSION:
+				{
+#ifdef HAVE_LIBZ
+					size = compressBound(BLCKSZ) + sizeof(CompressHeader);
+#endif
+					break;
+				}
+
 			case TEMP_PGLZ_COMPRESSION:
 				size = pglz_maximum_compressed_size(BLCKSZ, BLCKSZ) + sizeof(CompressHeader);
 				break;
@@ -689,6 +703,20 @@ BufFileLoadBuffer(BufFile *file)
 #endif
 						break;
 
+					case TEMP_GZIP_COMPRESSION:
+#ifdef HAVE_LIBZ
+						int		ret;
+						size_t	len = sizeof(file->buffer);
+
+						ret = uncompress((uint8 *) file->buffer.data, &len,
+										 (uint8 *) buff, header.len);
+						if (ret != Z_OK)
+							elog(ERROR, "uncompress failed");
+
+						file->nbytes = len;
+#endif
+						break;
+
 					case TEMP_PGLZ_COMPRESSION:
 						file->nbytes = pglz_decompress(buff, header.len,
 													   file->buffer.data, header.raw_len, false);
@@ -785,6 +813,28 @@ BufFileDumpBuffer(BufFile *file)
 								 errmsg_internal("compression failed, compressed size %d, original size %d",
 												 cSize, nbytesOriginal)));
 					}
+#endif
+					break;
+				}
+			case TEMP_GZIP_COMPRESSION:
+				{
+#ifdef HAVE_LIBZ
+					int			ret;
+					size_t		len = compressBound(file->nbytes);
+
+					/* XXX maybe lower level? the default is pretty slow ... */
+					ret = compress2((uint8 *) (cData + sizeof(CompressHeader)), &len,
+									(uint8 *) file->buffer.data, file->nbytes,
+									Z_DEFAULT_COMPRESSION);
+					if (ret != Z_OK)
+					{
+						ereport(ERROR,
+								(errcode(ERRCODE_DATA_CORRUPTED),
+								 errmsg_internal("compression failed, compressed size %d, original size %d",
+												 cSize, nbytesOriginal)));
+					}
+
+					cSize = len;
 #endif
 					break;
 				}
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index 2fb3891b730..88fbe405d59 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -473,6 +473,9 @@ static const struct config_enum_entry temp_file_compression_options[] = {
 	{"pglz", TEMP_PGLZ_COMPRESSION, false},
 #ifdef  USE_LZ4
 	{"lz4", TEMP_LZ4_COMPRESSION, false},
+#endif
+#ifdef  HAVE_LIBZ
+	{"gzip", TEMP_GZIP_COMPRESSION, false},
 #endif
 	{NULL, 0, false}
 };
diff --git a/src/include/storage/buffile.h b/src/include/storage/buffile.h
index 49594f1948e..7a1bb1d6085 100644
--- a/src/include/storage/buffile.h
+++ b/src/include/storage/buffile.h
@@ -36,7 +36,8 @@ typedef enum
 {
 	TEMP_NONE_COMPRESSION,
 	TEMP_PGLZ_COMPRESSION,
-	TEMP_LZ4_COMPRESSION
+	TEMP_LZ4_COMPRESSION,
+	TEMP_GZIP_COMPRESSION
 } TempCompression;
 
 extern PGDLLIMPORT int temp_file_compression;
-- 
2.51.0

