v2-0001-Add-pg_get_injection_points.patch
text/x-diff
Filename: v2-0001-Add-pg_get_injection_points.patch
Type: text/x-diff
Part: 0
Patch
Format: format-patch
Series: patch v2-0001
Subject: Add pg_get_injection_points()
| File | + | − |
|---|---|---|
| doc/src/sgml/func.sgml | 46 | 0 |
| src/backend/utils/misc/injection_point.c | 53 | 0 |
| src/backend/utils/misc/injection_point_funcs.c | 59 | 0 |
| src/backend/utils/misc/Makefile | 1 | 0 |
| src/backend/utils/misc/meson.build | 1 | 0 |
| src/include/catalog/pg_proc.dat | 8 | 0 |
| src/include/utils/injection_point.h | 14 | 0 |
| src/test/modules/injection_points/expected/injection_points.out | 16 | 0 |
| src/test/modules/injection_points/sql/injection_points.sql | 7 | 0 |
| src/test/regress/expected/misc_functions.out | 7 | 0 |
| src/test/regress/sql/misc_functions.sql | 3 | 0 |
| src/tools/pgindent/typedefs.list | 1 | 0 |
From ee033a0f883d52638cc9c90b9c0eff29b9dde5a5 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Tue, 15 Apr 2025 08:39:36 +0900
Subject: [PATCH v2] 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/include/utils/injection_point.h | 14 +++++
src/backend/utils/misc/Makefile | 1 +
src/backend/utils/misc/injection_point.c | 53 +++++++++++++++++
.../utils/misc/injection_point_funcs.c | 59 +++++++++++++++++++
src/backend/utils/misc/meson.build | 1 +
.../expected/injection_points.out | 16 +++++
.../injection_points/sql/injection_points.sql | 7 +++
src/test/regress/expected/misc_functions.out | 7 +++
src/test/regress/sql/misc_functions.sql | 3 +
doc/src/sgml/func.sgml | 46 +++++++++++++++
src/tools/pgindent/typedefs.list | 1 +
12 files changed, 216 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 62beb71da288..d087d9fda1e8 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -12566,4 +12566,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/include/utils/injection_point.h b/src/include/utils/injection_point.h
index 6ba64cd1ebc6..c5c78914b848 100644
--- a/src/include/utils/injection_point.h
+++ b/src/include/utils/injection_point.h
@@ -11,6 +11,17 @@
#ifndef INJECTION_POINT_H
#define INJECTION_POINT_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.
*/
@@ -46,6 +57,9 @@ extern void InjectionPointCached(const char *name);
extern bool IsInjectionPointAttached(const char *name);
extern bool InjectionPointDetach(const char *name);
+/* Get the current set of injection points attached */
+extern InjectionPointData *InjectionPointList(uint32 *num_points);
+
#ifdef EXEC_BACKEND
extern PGDLLIMPORT struct InjectionPointsCtl *ActiveInjectionPoints;
#endif
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.c b/src/backend/utils/misc/injection_point.c
index 97ab851f0a63..ea7e6dba5211 100644
--- a/src/backend/utils/misc/injection_point.c
+++ b/src/backend/utils/misc/injection_point.c
@@ -584,3 +584,56 @@ 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.
+ */
+InjectionPointData *
+InjectionPointList(uint32 *num_points)
+{
+#ifdef USE_INJECTION_POINTS
+ InjectionPointData *result;
+ uint32 max_inuse;
+ int cur_pos = 0;
+
+ LWLockAcquire(InjectionPointLock, LW_SHARED);
+
+ max_inuse = pg_atomic_read_u32(&ActiveInjectionPoints->max_inuse);
+
+ /*
+ * This overestimates the allocation size, including slots that may be
+ * free, for simplicity.
+ */
+ result = palloc0(sizeof(InjectionPointData) * max_inuse);
+
+ for (int idx = 0; idx < max_inuse; idx++)
+ {
+ InjectionPointEntry *entry;
+ uint64 generation;
+
+ entry = &ActiveInjectionPoints->entries[idx];
+ generation = pg_atomic_read_u64(&entry->generation);
+
+ /* skip free slots */
+ if (generation % 2 == 0)
+ continue;
+
+ result[cur_pos].name = pstrdup(entry->name);
+ result[cur_pos].library = pstrdup(entry->library);
+ result[cur_pos].function = pstrdup(entry->function);
+ cur_pos++;
+ }
+
+ LWLockRelease(InjectionPointLock);
+
+ *num_points = cur_pos;
+
+ return result;
+
+#else
+ *num_points = 0;
+ return NULL;
+#endif
+}
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..750ac4abf67d
--- /dev/null
+++ b/src/backend/utils/misc/injection_point_funcs.c
@@ -0,0 +1,59 @@
+/*-------------------------------------------------------------------------
+ *
+ * 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;
+ uint32 num_points = 0;
+ InjectionPointData *injps = NULL;
+
+ /* Build a tuplestore to return our results in */
+ InitMaterializedSRF(fcinfo, 0);
+
+ injps = InjectionPointList(&num_points);
+
+ for (uint32 idx = 0; idx < num_points; idx++)
+ {
+ Datum values[NUM_PG_GET_INJECTION_POINTS];
+ bool nulls[NUM_PG_GET_INJECTION_POINTS];
+
+ memset(values, 0, sizeof(values));
+ memset(nulls, 0, sizeof(nulls));
+
+ values[0] = PointerGetDatum(cstring_to_text(injps[idx].name));
+ values[1] = PointerGetDatum(cstring_to_text(injps[idx].library));
+ values[2] = PointerGetDatum(cstring_to_text(injps[idx].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 f25bbe4966ee..4b1436a3ef69 100644
--- a/src/test/modules/injection_points/expected/injection_points.out
+++ b/src/test/modules/injection_points/expected/injection_points.out
@@ -26,6 +26,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
----------------------
@@ -253,5 +262,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 e3a481d60449..b12c40551954 100644
--- a/src/test/modules/injection_points/sql/injection_points.sql
+++ b/src/test/modules/injection_points/sql/injection_points.sql
@@ -14,6 +14,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('TestInjectionLog'); -- notice
@@ -75,5 +78,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/src/test/regress/expected/misc_functions.out b/src/test/regress/expected/misc_functions.out
index d3f5d16a6725..c09bff495045 100644
--- a/src/test/regress/expected/misc_functions.out
+++ b/src/test/regress/expected/misc_functions.out
@@ -802,6 +802,13 @@ SELECT count(*) > 0 AS ok FROM pg_control_system();
t
(1 row)
+-- Test function for injection point
+SELECT count(*) >= 0 AS ok FROM pg_get_injection_points();
+ ok
+----
+ t
+(1 row)
+
-- pg_split_walfile_name, pg_walfile_name & pg_walfile_name_offset
SELECT * FROM pg_split_walfile_name(NULL);
segment_number | timeline_id
diff --git a/src/test/regress/sql/misc_functions.sql b/src/test/regress/sql/misc_functions.sql
index aaebb298330b..e351a19a8744 100644
--- a/src/test/regress/sql/misc_functions.sql
+++ b/src/test/regress/sql/misc_functions.sql
@@ -355,6 +355,9 @@ SELECT count(*) > 0 AS ok FROM pg_control_init();
SELECT count(*) > 0 AS ok FROM pg_control_recovery();
SELECT count(*) > 0 AS ok FROM pg_control_system();
+-- Test function for injection point
+SELECT count(*) >= 0 AS ok FROM pg_get_injection_points();
+
-- pg_split_walfile_name, pg_walfile_name & pg_walfile_name_offset
SELECT * FROM pg_split_walfile_name(NULL);
SELECT * FROM pg_split_walfile_name('invalid');
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 1c5cfee25d12..6c0e0b45fa83 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -28496,6 +28496,52 @@ 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.
+ </para></entry>
+ </row>
+ </tbody>
+
+ </tgroup>
+ </table>
+ </sect2>
+
</sect1>
<sect1 id="functions-admin">
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index d16bc208654b..e7df2dc10684 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1281,6 +1281,7 @@ InjectionPointCacheEntry
InjectionPointCallback
InjectionPointCondition
InjectionPointConditionType
+InjectionPointData
InjectionPointEntry
InjectionPointsCtl
InjectionPointSharedState
--
2.49.0