into backend-private memory if it is
active. Inside the critical section, use
<function>INJECTION_POINT_CACHED</function> to execute the callback.
</para>
<para>
Add-ins can attach callbacks to an already-declared injection point by
calling:
<programlisting>
extern void InjectionPointAttach(const char *name,
const char *library,
const char *function,
const void *private_data,
int private_data_size);
</programlisting>
<literal>name</literal> is the name of the injection point, which when
reached during execution will execute the <literal>function</literal>
loaded from <literal>library</literal>. <literal>private_data</literal>
is a private area of data of size <literal>private_data_size</literal>
given as argument to the callback when executed.
</para>
<para>
Here is an example of callback for
<literal>InjectionPointCallback</literal>:
<programlisting>
static void
custom_injection_callback(const char *name,
const void *private_data,
void *arg)
{
uint32 wait_event_info = WaitEventInjectionPointNew(name);
pgstat_report_wait_start(wait_event_info);
elog(NOTICE, "%s: executed custom callback", name);
pgstat_report_wait_end();
}
</programlisting>
This callback prints a message to server error log with severity
<literal>NOTICE</literal>, but callbacks may implement more complex
logic.
</para>
<para>
An alternative way to define the action to take when an injection point
is reached is to add the testing code alongside the normal source
code. This can be useful if the action e.g. depends on local variables
that are not accessible to loaded modules. The
<function>IS_INJECTION_POINT_ATTACHED</function> macro can then be used
to check if an injection point is attached, for example:
<programlisting>
#ifdef USE_INJECTION_POINTS
if (IS_INJECTION_POINT_ATTACHED("before-foobar"))
{
/* change a local variable if injection point is attached */
local_var = 123;
/* also execute the callback */
INJECTION_POINT_CACHED("before-foobar", NULL);
}
#endif
</programlisting>
Note that the callback attached to the injection point will not be
executed by the <function>IS_INJECTION_POINT_ATTACHED</function>
macro. If you want to execute the callback, you must also call
<function>INJECTION_POINT_CACHED</function> like in the above example.
</para>
<para>
Optionally, it is possible to detach an injection point by calling:
<programlisting>
extern bool InjectionPointDetach(const char *name);
</programlisting>
On success, <literal>true</literal> is returned, <literal>false</literal>
otherwise.
</para>
<para>
A callback attached to an injection point is available across all the
backends including the backends started after
<literal>InjectionPointAttach</literal> is called. It remains attached
while the server is running or until the injection point is detached
using <literal>InjectionPointDetach</literal>.
</para>
<para>
An example can be found in
<filename>src/test/modules/injection_points</filename> in the PostgreSQL
source tree.
</para>
<para>
Enabling injections points requires
<option>--enable-injection-points</option> with
<command>configure</command> or <option>-Dinjection_points=true</option>
with <application>Meson</application>.
</para>
</sect2>
<sect2 id="xfunc-addin-custom-cumulative-statistics">
<title>Custom Cumulative Statistics</title>
<para>
It is possible for add-ins written in C-language to use custom types
of cumulative statistics registered in the
<link linkend="monitoring-stats-setup">Cumulative Statistics System</link>.
</para>
<para>