From 776ef0cfffa2a774bf255c4707da4f2af2b7bd06 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Wed, 16 Jul 2025 12:06:57 +0900
Subject: [PATCH 1/2] Add function pg_compression_available

This is able to check if compression methods are available in a given
build, in a platform and build-transparent manner.  The values that can
be checked in the backend are: gzip, pglz, lz4 and zstd.

This function will be useful in an upcoming patch that refactors the
TOAST tests.
---
 src/include/catalog/pg_proc.dat              |  4 ++
 src/backend/utils/adt/misc.c                 | 51 ++++++++++++++++++++
 src/test/regress/expected/misc_functions.out | 15 ++++++
 src/test/regress/sql/misc_functions.sql      |  5 ++
 doc/src/sgml/func.sgml                       | 18 +++++++
 5 files changed, 93 insertions(+)

diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 1fc19146f467..6b3aaba4a90e 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6876,6 +6876,10 @@
 { oid => '315', descr => 'Is JIT compilation available in this session?',
   proname => 'pg_jit_available', provolatile => 'v', prorettype => 'bool',
   proargtypes => '', prosrc => 'pg_jit_available' },
+{ oid =>  9474, descr => 'Is compression method available?',
+  proname => 'pg_compression_available', prokind => 'f',
+  provolatile => 'i', prorettype => 'bool', proargtypes => 'text',
+  prosrc => 'pg_compression_available' },
 
 { oid => '2971', descr => 'convert boolean to text',
   proname => 'text', prorettype => 'text', proargtypes => 'bool',
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 6fcfd031428e..a41b19c6250a 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -1122,3 +1122,54 @@ any_value_transfn(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_DATUM(PG_GETARG_DATUM(0));
 }
+
+/*
+ * pg_compression_available
+ *
+ * True if the named compression method is available in this server.
+ */
+Datum
+pg_compression_available(PG_FUNCTION_ARGS)
+{
+	text	   *name = PG_GETARG_TEXT_PP(0);
+	char	   *cname = downcase_truncate_identifier(text_to_cstring(name),
+													 NAMEDATALEN, false);
+
+	/* pglz is always there */
+	if (strcmp(cname, "pglz") == 0)
+		PG_RETURN_BOOL(true);
+
+	if (strcmp(cname, "gzip") == 0)
+	{
+#ifdef HAVE_LIBZ
+		PG_RETURN_BOOL(true);
+#else
+		PG_RETURN_BOOL(false);
+#endif
+	}
+
+	if (strcmp(cname, "lz4") == 0)
+	{
+#ifdef USE_LZ4
+		PG_RETURN_BOOL(true);
+#else
+		PG_RETURN_BOOL(false);
+#endif
+	}
+
+	if (strcmp(cname, "zstd") == 0)
+	{
+#ifdef USE_ZSTD
+		PG_RETURN_BOOL(true);
+#else
+		PG_RETURN_BOOL(false);
+#endif
+	}
+
+	ereport(ERROR,
+			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+			 errmsg("%s compression is not supported by this build",
+					cname)));
+
+	PG_RETURN_BOOL(false);	/* keep compiler quiet */
+}
diff --git a/src/test/regress/expected/misc_functions.out b/src/test/regress/expected/misc_functions.out
index c3b2b9d86034..8158839fc6f2 100644
--- a/src/test/regress/expected/misc_functions.out
+++ b/src/test/regress/expected/misc_functions.out
@@ -918,3 +918,18 @@ SELECT test_relpath();
 SELECT pg_replication_origin_create('regress_' || repeat('a', 505));
 ERROR:  replication origin name is too long
 DETAIL:  Replication origin names must be no longer than 512 bytes.
+-- pg_compression_available
+SELECT pg_compression_available(NULL);
+ pg_compression_available 
+--------------------------
+ 
+(1 row)
+
+SELECT pg_compression_available('pglz');
+ pg_compression_available 
+--------------------------
+ t
+(1 row)
+
+SELECT pg_compression_available('non_existent');
+ERROR:  non_existent compression is not supported by this build
diff --git a/src/test/regress/sql/misc_functions.sql b/src/test/regress/sql/misc_functions.sql
index 23792c4132a1..5a59eb35197b 100644
--- a/src/test/regress/sql/misc_functions.sql
+++ b/src/test/regress/sql/misc_functions.sql
@@ -414,3 +414,8 @@ SELECT test_relpath();
 
 -- pg_replication_origin.roname limit
 SELECT pg_replication_origin_create('regress_' || repeat('a', 505));
+
+-- pg_compression_available
+SELECT pg_compression_available(NULL);
+SELECT pg_compression_available('pglz');
+SELECT pg_compression_available('non_existent');
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index f5a0e0954a15..ddeda431b2be 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -25020,6 +25020,24 @@ SELECT * FROM pg_ls_dir('.') WITH ORDINALITY AS t(ls,n);
        </para></entry>
       </row>
 
+      <row>
+       <entry role="func_table_entry"><para role="func_signature">
+        <indexterm>
+         <primary>pg_compression_available</primary>
+        </indexterm>
+        <function>pg_compression_available</function> ( <type>text</type> )
+        <returnvalue>boolean</returnvalue>
+        </para>
+        <para>
+         Returns <literal>true</literal> if the given compression method name
+         is supported in the <productname>PostgreSQL</productname> build.
+         The supported compression methods that can be checked are
+         <literal>gzip</literal>, <literal>pglz</literal> (always available),
+         <literal>lz4</literal> and <literal>zstd</literal>.
+        </para>
+       </entry>
+      </row>
+
       <row>
        <entry role="func_table_entry"><para role="func_signature">
         <indexterm>
-- 
2.50.0

