On Sun, May 25, 2025 at 03:59:51AM +0000, Rustam ALLAKOV wrote:
> to match how `unicode_version` function is documented
> > Returns a string representing the version of Unicode used by ICU, if
> > the server was built with ICU support; otherwise returns

Makes sense, with the difference that the function throws an error if
Postgres is configured without --enable-injection-points.
--
Michael
From 3f85f040d1e00cb3c3802cab1b8baae0a0d59e95 Mon Sep 17 00:00:00 2001
From: Michael Paquier <mich...@paquier.xyz>
Date: Tue, 22 Apr 2025 12:59:30 +0900
Subject: [PATCH v5 1/2] Add InjectionPointList() to retrieve list of injection
 points

This hides the internals of the shmem array lookup, allocating the
result in a palloc'd array usable by the caller.
---
 src/include/utils/injection_point.h      | 16 +++++++++
 src/backend/utils/misc/injection_point.c | 46 ++++++++++++++++++++++++
 src/tools/pgindent/typedefs.list         |  1 +
 3 files changed, 63 insertions(+)

diff --git a/src/include/utils/injection_point.h b/src/include/utils/injection_point.h
index a37958e1835f..fd5bc061b7bd 100644
--- a/src/include/utils/injection_point.h
+++ b/src/include/utils/injection_point.h
@@ -11,6 +11,19 @@
 #ifndef INJECTION_POINT_H
 #define INJECTION_POINT_H
 
+#include "nodes/pg_list.h"
+
+/*
+ * Injection point data, used when retrieving a list of all the attached
+ * injection points.
+ */
+typedef struct InjectionPointData
+{
+	const char *name;
+	const char *library;
+	const char *function;
+} InjectionPointData;
+
 /*
  * Injection points require --enable-injection-points.
  */
@@ -47,6 +60,9 @@ extern void InjectionPointCached(const char *name, void *arg);
 extern bool IsInjectionPointAttached(const char *name);
 extern bool InjectionPointDetach(const char *name);
 
+/* Get the current set of injection points attached */
+extern List *InjectionPointList(void);
+
 #ifdef EXEC_BACKEND
 extern PGDLLIMPORT struct InjectionPointsCtl *ActiveInjectionPoints;
 #endif
diff --git a/src/backend/utils/misc/injection_point.c b/src/backend/utils/misc/injection_point.c
index f58ebc8ee522..12570fba56e4 100644
--- a/src/backend/utils/misc/injection_point.c
+++ b/src/backend/utils/misc/injection_point.c
@@ -584,3 +584,49 @@ IsInjectionPointAttached(const char *name)
 	return false;				/* silence compiler */
 #endif
 }
+
+/*
+ * Retrieve a list of all the injection points currently attached.
+ *
+ * This list is palloc'd in the current memory context.
+ */
+List *
+InjectionPointList(void)
+{
+#ifdef USE_INJECTION_POINTS
+	List	   *inj_points = NIL;
+	uint32		max_inuse;
+
+	LWLockAcquire(InjectionPointLock, LW_SHARED);
+
+	max_inuse = pg_atomic_read_u32(&ActiveInjectionPoints->max_inuse);
+
+	for (uint32 idx = 0; idx < max_inuse; idx++)
+	{
+		InjectionPointEntry *entry;
+		InjectionPointData *inj_point;
+		uint64		generation;
+
+		entry = &ActiveInjectionPoints->entries[idx];
+		generation = pg_atomic_read_u64(&entry->generation);
+
+		/* skip free slots */
+		if (generation % 2 == 0)
+			continue;
+
+		inj_point = (InjectionPointData *) palloc0(sizeof(InjectionPointData));
+		inj_point->name = pstrdup(entry->name);
+		inj_point->library = pstrdup(entry->library);
+		inj_point->function = pstrdup(entry->function);
+		inj_points = lappend(inj_points, inj_point);
+	}
+
+	LWLockRelease(InjectionPointLock);
+
+	return inj_points;
+
+#else
+	elog(ERROR, "Injection points are not supported by this build");
+	return NIL;	/* keep compiler quiet */
+#endif
+}
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index a8346cda633a..4ad6fdb0d003 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1283,6 +1283,7 @@ InjectionPointCacheEntry
 InjectionPointCallback
 InjectionPointCondition
 InjectionPointConditionType
+InjectionPointData
 InjectionPointEntry
 InjectionPointsCtl
 InjectionPointSharedState
-- 
2.49.0

From 82aa223a25a7bbd19e6bc2c873d3b8d5e5398870 Mon Sep 17 00:00:00 2001
From: Michael Paquier <mich...@paquier.xyz>
Date: Tue, 27 May 2025 16:07:08 +0900
Subject: [PATCH v5 2/2] Add pg_get_injection_points()

This is a system function that displays the information about the
injection points currently attached to the system, feeding from the
states of things in shared memory.
---
 src/include/catalog/pg_proc.dat               |  8 +++
 src/backend/utils/misc/Makefile               |  1 +
 .../utils/misc/injection_point_funcs.c        | 60 +++++++++++++++++++
 src/backend/utils/misc/meson.build            |  1 +
 .../expected/injection_points.out             | 16 +++++
 .../injection_points/sql/injection_points.sql |  7 +++
 doc/src/sgml/func.sgml                        | 48 +++++++++++++++
 7 files changed, 141 insertions(+)
 create mode 100644 src/backend/utils/misc/injection_point_funcs.c

diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 37a484147a8f..eb9c6cd16263 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -12556,4 +12556,12 @@
   proargnames => '{pid,io_id,io_generation,state,operation,off,length,target,handle_data_len,raw_result,result,target_desc,f_sync,f_localmem,f_buffered}',
   prosrc => 'pg_get_aios' },
 
+# Injection point functions
+{ oid => '8490', descr => 'information about injection points attached',
+  proname => 'pg_get_injection_points', prorows => '3', proretset => 't',
+  provolatile => 'v', proparallel => 'r', prorettype => 'record',
+  proargtypes => '', proallargtypes => '{text,text,text}',
+  proargmodes => '{o,o,o}', proargnames => '{name,library,function}',
+  prosrc => 'pg_get_injection_points' },
+
 ]
diff --git a/src/backend/utils/misc/Makefile b/src/backend/utils/misc/Makefile
index b362ae437710..93703633f69a 100644
--- a/src/backend/utils/misc/Makefile
+++ b/src/backend/utils/misc/Makefile
@@ -22,6 +22,7 @@ OBJS = \
 	guc_tables.o \
 	help_config.o \
 	injection_point.o \
+	injection_point_funcs.o \
 	pg_config.o \
 	pg_controldata.o \
 	pg_rusage.o \
diff --git a/src/backend/utils/misc/injection_point_funcs.c b/src/backend/utils/misc/injection_point_funcs.c
new file mode 100644
index 000000000000..c7cd02a517da
--- /dev/null
+++ b/src/backend/utils/misc/injection_point_funcs.c
@@ -0,0 +1,60 @@
+/*-------------------------------------------------------------------------
+ *
+ * injection_point_funcs.c
+ *
+ * SQL commands and SQL-accessible functions related to injection points.
+ *
+ * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  src/backend/utils/misc/injection_point_funcs.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "funcapi.h"
+#include "utils/builtins.h"
+#include "utils/injection_point.h"
+
+/*
+ * pg_get_injection_points
+ *
+ * Return a table of all the injection points currently attached to the
+ * system.
+ */
+Datum
+pg_get_injection_points(PG_FUNCTION_ARGS)
+{
+#define NUM_PG_GET_INJECTION_POINTS 3
+	ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+	List *inj_points;
+	ListCell *lc;
+
+	/* Build a tuplestore to return our results in */
+	InitMaterializedSRF(fcinfo, 0);
+
+	inj_points = InjectionPointList();
+
+	foreach(lc, inj_points)
+	{
+		Datum		values[NUM_PG_GET_INJECTION_POINTS];
+		bool		nulls[NUM_PG_GET_INJECTION_POINTS];
+		InjectionPointData *inj_point = lfirst(lc);
+
+		memset(values, 0, sizeof(values));
+		memset(nulls, 0, sizeof(nulls));
+
+		values[0] = PointerGetDatum(cstring_to_text(inj_point->name));
+		values[1] = PointerGetDatum(cstring_to_text(inj_point->library));
+		values[2] = PointerGetDatum(cstring_to_text(inj_point->function));
+
+		/* shove row into tuplestore */
+		tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
+	}
+
+	return (Datum) 0;
+#undef NUM_PG_GET_INJECTION_POINTS
+}
diff --git a/src/backend/utils/misc/meson.build b/src/backend/utils/misc/meson.build
index 9e389a00d057..4a89f1e016ea 100644
--- a/src/backend/utils/misc/meson.build
+++ b/src/backend/utils/misc/meson.build
@@ -7,6 +7,7 @@ backend_sources += files(
   'guc_tables.c',
   'help_config.c',
   'injection_point.c',
+  'injection_point_funcs.c',
   'pg_config.c',
   'pg_controldata.c',
   'pg_rusage.c',
diff --git a/src/test/modules/injection_points/expected/injection_points.out b/src/test/modules/injection_points/expected/injection_points.out
index 43bcdd01582f..e59065029b41 100644
--- a/src/test/modules/injection_points/expected/injection_points.out
+++ b/src/test/modules/injection_points/expected/injection_points.out
@@ -39,6 +39,15 @@ SELECT injection_points_attach('TestInjectionLog2', 'notice');
  
 (1 row)
 
+SELECT name, library, function FROM pg_get_injection_points()
+  ORDER BY name COLLATE "C";
+        name        |     library      |     function     
+--------------------+------------------+------------------
+ TestInjectionError | injection_points | injection_error
+ TestInjectionLog   | injection_points | injection_notice
+ TestInjectionLog2  | injection_points | injection_notice
+(3 rows)
+
 SELECT injection_points_run('TestInjectionBooh'); -- nothing
  injection_points_run 
 ----------------------
@@ -298,5 +307,12 @@ SELECT injection_points_detach('TestConditionLocal1');
  
 (1 row)
 
+-- No points should be left around.
+SELECT name, library, function FROM pg_get_injection_points()
+  ORDER BY name COLLATE "C";
+ name | library | function 
+------+---------+----------
+(0 rows)
+
 DROP EXTENSION injection_points;
 DROP FUNCTION wait_pid;
diff --git a/src/test/modules/injection_points/sql/injection_points.sql b/src/test/modules/injection_points/sql/injection_points.sql
index d9748331c771..2b5f28b73a60 100644
--- a/src/test/modules/injection_points/sql/injection_points.sql
+++ b/src/test/modules/injection_points/sql/injection_points.sql
@@ -18,6 +18,9 @@ SELECT injection_points_attach('TestInjectionError', 'error');
 SELECT injection_points_attach('TestInjectionLog', 'notice');
 SELECT injection_points_attach('TestInjectionLog2', 'notice');
 
+SELECT name, library, function FROM pg_get_injection_points()
+  ORDER BY name COLLATE "C";
+
 SELECT injection_points_run('TestInjectionBooh'); -- nothing
 SELECT injection_points_run('TestInjectionLog2'); -- notice
 SELECT injection_points_run('TestInjectionLog2', NULL); -- notice
@@ -85,5 +88,9 @@ SELECT injection_points_detach('TestConditionError');
 SELECT injection_points_attach('TestConditionLocal1', 'error');
 SELECT injection_points_detach('TestConditionLocal1');
 
+-- No points should be left around.
+SELECT name, library, function FROM pg_get_injection_points()
+  ORDER BY name COLLATE "C";
+
 DROP EXTENSION injection_points;
 DROP FUNCTION wait_pid;
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index c67688cbf5f9..8e38d429c776 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -28496,6 +28496,54 @@ acl      | {postgres=arwdDxtm/postgres,foo=r/postgres}
 
   </sect2>
 
+  <sect2 id="functions-info-injection-points">
+   <title>Injection Points Information Functions</title>
+
+   <para>
+    The functions shown in <xref linkend="functions-info-injection-points"/>
+    print information about the injection points.
+    See <xref linkend="xfunc-addin-injection-points" />.
+   </para>
+
+   <table id="functions-injection-points">
+    <title>WAL Summarization Information Functions</title>
+    <tgroup cols="1">
+     <thead>
+      <row>
+       <entry role="func_table_entry"><para role="func_signature">
+        Function
+       </para>
+       <para>
+        Description
+       </para></entry>
+      </row>
+     </thead>
+
+     <tbody>
+      <row>
+       <entry role="func_table_entry"><para role="func_signature">
+        <indexterm>
+         <primary>pg_get_injection_points</primary>
+        </indexterm>
+        <function>pg_get_injection_points</function> ()
+        <returnvalue>setof record</returnvalue>
+        ( <parameter>name</parameter> <type>text</type>,
+        <parameter>library</parameter> <type>text</type>,
+        <parameter>function</parameter> <type>text</type> )
+       </para>
+       <para>
+        Returns information about the injection points currently attached
+        to the cluster, if the server was built with the configure option
+        <option>--enable-injection-points</option>; otherwise throws
+        an error.
+       </para></entry>
+      </row>
+     </tbody>
+
+    </tgroup>
+   </table>
+  </sect2>
+
   </sect1>
 
   <sect1 id="functions-admin">
-- 
2.49.0

Attachment: signature.asc
Description: PGP signature

Reply via email to