summaryrefslogtreecommitdiffstats
path: root/doc/src/sgml/html/libpq-events.html
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 13:44:03 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 13:44:03 +0000
commit293913568e6a7a86fd1479e1cff8e2ecb58d6568 (patch)
treefc3b469a3ec5ab71b36ea97cc7aaddb838423a0c /doc/src/sgml/html/libpq-events.html
parentInitial commit. (diff)
downloadpostgresql-16-293913568e6a7a86fd1479e1cff8e2ecb58d6568.tar.xz
postgresql-16-293913568e6a7a86fd1479e1cff8e2ecb58d6568.zip
Adding upstream version 16.2.upstream/16.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'doc/src/sgml/html/libpq-events.html')
-rw-r--r--doc/src/sgml/html/libpq-events.html425
1 files changed, 425 insertions, 0 deletions
diff --git a/doc/src/sgml/html/libpq-events.html b/doc/src/sgml/html/libpq-events.html
new file mode 100644
index 0000000..a29107f
--- /dev/null
+++ b/doc/src/sgml/html/libpq-events.html
@@ -0,0 +1,425 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>34.14. Event System</title><link rel="stylesheet" type="text/css" href="stylesheet.css" /><link rev="made" href="pgsql-docs@lists.postgresql.org" /><meta name="generator" content="DocBook XSL Stylesheets Vsnapshot" /><link rel="prev" href="libpq-notice-processing.html" title="34.13. Notice Processing" /><link rel="next" href="libpq-envars.html" title="34.15. Environment Variables" /></head><body id="docContent" class="container-fluid col-10"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="5" align="center">34.14. Event System</th></tr><tr><td width="10%" align="left"><a accesskey="p" href="libpq-notice-processing.html" title="34.13. Notice Processing">Prev</a> </td><td width="10%" align="left"><a accesskey="u" href="libpq.html" title="Chapter 34. libpq — C Library">Up</a></td><th width="60%" align="center">Chapter 34. <span class="application">libpq</span> — C Library</th><td width="10%" align="right"><a accesskey="h" href="index.html" title="PostgreSQL 16.2 Documentation">Home</a></td><td width="10%" align="right"> <a accesskey="n" href="libpq-envars.html" title="34.15. Environment Variables">Next</a></td></tr></table><hr /></div><div class="sect1" id="LIBPQ-EVENTS"><div class="titlepage"><div><div><h2 class="title" style="clear: both">34.14. Event System <a href="#LIBPQ-EVENTS" class="id_link">#</a></h2></div></div></div><div class="toc"><dl class="toc"><dt><span class="sect2"><a href="libpq-events.html#LIBPQ-EVENTS-TYPES">34.14.1. Event Types</a></span></dt><dt><span class="sect2"><a href="libpq-events.html#LIBPQ-EVENTS-PROC">34.14.2. Event Callback Procedure</a></span></dt><dt><span class="sect2"><a href="libpq-events.html#LIBPQ-EVENTS-FUNCS">34.14.3. Event Support Functions</a></span></dt><dt><span class="sect2"><a href="libpq-events.html#LIBPQ-EVENTS-EXAMPLE">34.14.4. Event Example</a></span></dt></dl></div><p>
+ <span class="application">libpq</span>'s event system is designed to notify
+ registered event handlers about interesting
+ <span class="application">libpq</span> events, such as the creation or
+ destruction of <code class="structname">PGconn</code> and
+ <code class="structname">PGresult</code> objects. A principal use case is that
+ this allows applications to associate their own data with a
+ <code class="structname">PGconn</code> or <code class="structname">PGresult</code>
+ and ensure that that data is freed at an appropriate time.
+ </p><p>
+ Each registered event handler is associated with two pieces of data,
+ known to <span class="application">libpq</span> only as opaque <code class="literal">void *</code>
+ pointers. There is a <em class="firstterm">pass-through</em> pointer that is provided
+ by the application when the event handler is registered with a
+ <code class="structname">PGconn</code>. The pass-through pointer never changes for the
+ life of the <code class="structname">PGconn</code> and all <code class="structname">PGresult</code>s
+ generated from it; so if used, it must point to long-lived data.
+ In addition there is an <em class="firstterm">instance data</em> pointer, which starts
+ out <code class="symbol">NULL</code> in every <code class="structname">PGconn</code> and <code class="structname">PGresult</code>.
+ This pointer can be manipulated using the
+ <a class="xref" href="libpq-events.html#LIBPQ-PQINSTANCEDATA"><code class="function">PQinstanceData</code></a>,
+ <a class="xref" href="libpq-events.html#LIBPQ-PQSETINSTANCEDATA"><code class="function">PQsetInstanceData</code></a>,
+ <a class="xref" href="libpq-events.html#LIBPQ-PQRESULTINSTANCEDATA"><code class="function">PQresultInstanceData</code></a> and
+ <a class="xref" href="libpq-events.html#LIBPQ-PQRESULTSETINSTANCEDATA"><code class="function">PQresultSetInstanceData</code></a> functions. Note that
+ unlike the pass-through pointer, instance data of a <code class="structname">PGconn</code>
+ is not automatically inherited by <code class="structname">PGresult</code>s created from
+ it. <span class="application">libpq</span> does not know what pass-through
+ and instance data pointers point to (if anything) and will never attempt
+ to free them — that is the responsibility of the event handler.
+ </p><div class="sect2" id="LIBPQ-EVENTS-TYPES"><div class="titlepage"><div><div><h3 class="title">34.14.1. Event Types <a href="#LIBPQ-EVENTS-TYPES" class="id_link">#</a></h3></div></div></div><p>
+ The enum <code class="literal">PGEventId</code> names the types of events handled by
+ the event system. All its values have names beginning with
+ <code class="literal">PGEVT</code>. For each event type, there is a corresponding
+ event info structure that carries the parameters passed to the event
+ handlers. The event types are:
+ </p><div class="variablelist"><dl class="variablelist"><dt id="LIBPQ-PGEVT-REGISTER"><span class="term"><code class="literal">PGEVT_REGISTER</code></span> <a href="#LIBPQ-PGEVT-REGISTER" class="id_link">#</a></dt><dd><p>
+ The register event occurs when <a class="xref" href="libpq-events.html#LIBPQ-PQREGISTEREVENTPROC"><code class="function">PQregisterEventProc</code></a>
+ is called. It is the ideal time to initialize any
+ <code class="literal">instanceData</code> an event procedure may need. Only one
+ register event will be fired per event handler per connection. If the
+ event procedure fails (returns zero), the registration is cancelled.
+
+</p><pre class="synopsis">
+typedef struct
+{
+ PGconn *conn;
+} PGEventRegister;
+</pre><p>
+
+ When a <code class="literal">PGEVT_REGISTER</code> event is received, the
+ <em class="parameter"><code>evtInfo</code></em> pointer should be cast to a
+ <code class="structname">PGEventRegister *</code>. This structure contains a
+ <code class="structname">PGconn</code> that should be in the
+ <code class="literal">CONNECTION_OK</code> status; guaranteed if one calls
+ <a class="xref" href="libpq-events.html#LIBPQ-PQREGISTEREVENTPROC"><code class="function">PQregisterEventProc</code></a> right after obtaining a good
+ <code class="structname">PGconn</code>. When returning a failure code, all
+ cleanup must be performed as no <code class="literal">PGEVT_CONNDESTROY</code>
+ event will be sent.
+ </p></dd><dt id="LIBPQ-PGEVT-CONNRESET"><span class="term"><code class="literal">PGEVT_CONNRESET</code></span> <a href="#LIBPQ-PGEVT-CONNRESET" class="id_link">#</a></dt><dd><p>
+ The connection reset event is fired on completion of
+ <a class="xref" href="libpq-connect.html#LIBPQ-PQRESET"><code class="function">PQreset</code></a> or <code class="function">PQresetPoll</code>. In
+ both cases, the event is only fired if the reset was successful.
+ The return value of the event procedure is ignored
+ in <span class="productname">PostgreSQL</span> v15 and later.
+ With earlier versions, however, it's important to return success
+ (nonzero) or the connection will be aborted.
+
+</p><pre class="synopsis">
+typedef struct
+{
+ PGconn *conn;
+} PGEventConnReset;
+</pre><p>
+
+ When a <code class="literal">PGEVT_CONNRESET</code> event is received, the
+ <em class="parameter"><code>evtInfo</code></em> pointer should be cast to a
+ <code class="structname">PGEventConnReset *</code>. Although the contained
+ <code class="structname">PGconn</code> was just reset, all event data remains
+ unchanged. This event should be used to reset/reload/requery any
+ associated <code class="literal">instanceData</code>. Note that even if the
+ event procedure fails to process <code class="literal">PGEVT_CONNRESET</code>, it will
+ still receive a <code class="literal">PGEVT_CONNDESTROY</code> event when the connection
+ is closed.
+ </p></dd><dt id="LIBPQ-PGEVT-CONNDESTROY"><span class="term"><code class="literal">PGEVT_CONNDESTROY</code></span> <a href="#LIBPQ-PGEVT-CONNDESTROY" class="id_link">#</a></dt><dd><p>
+ The connection destroy event is fired in response to
+ <a class="xref" href="libpq-connect.html#LIBPQ-PQFINISH"><code class="function">PQfinish</code></a>. It is the event procedure's
+ responsibility to properly clean up its event data as libpq has no
+ ability to manage this memory. Failure to clean up will lead
+ to memory leaks.
+
+</p><pre class="synopsis">
+typedef struct
+{
+ PGconn *conn;
+} PGEventConnDestroy;
+</pre><p>
+
+ When a <code class="literal">PGEVT_CONNDESTROY</code> event is received, the
+ <em class="parameter"><code>evtInfo</code></em> pointer should be cast to a
+ <code class="structname">PGEventConnDestroy *</code>. This event is fired
+ prior to <a class="xref" href="libpq-connect.html#LIBPQ-PQFINISH"><code class="function">PQfinish</code></a> performing any other cleanup.
+ The return value of the event procedure is ignored since there is no
+ way of indicating a failure from <a class="xref" href="libpq-connect.html#LIBPQ-PQFINISH"><code class="function">PQfinish</code></a>. Also,
+ an event procedure failure should not abort the process of cleaning up
+ unwanted memory.
+ </p></dd><dt id="LIBPQ-PGEVT-RESULTCREATE"><span class="term"><code class="literal">PGEVT_RESULTCREATE</code></span> <a href="#LIBPQ-PGEVT-RESULTCREATE" class="id_link">#</a></dt><dd><p>
+ The result creation event is fired in response to any query execution
+ function that generates a result, including
+ <a class="xref" href="libpq-async.html#LIBPQ-PQGETRESULT"><code class="function">PQgetResult</code></a>. This event will only be fired after
+ the result has been created successfully.
+
+</p><pre class="synopsis">
+typedef struct
+{
+ PGconn *conn;
+ PGresult *result;
+} PGEventResultCreate;
+</pre><p>
+
+ When a <code class="literal">PGEVT_RESULTCREATE</code> event is received, the
+ <em class="parameter"><code>evtInfo</code></em> pointer should be cast to a
+ <code class="structname">PGEventResultCreate *</code>. The
+ <em class="parameter"><code>conn</code></em> is the connection used to generate the
+ result. This is the ideal place to initialize any
+ <code class="literal">instanceData</code> that needs to be associated with the
+ result. If an event procedure fails (returns zero), that event
+ procedure will be ignored for the remaining lifetime of the result;
+ that is, it will not receive <code class="literal">PGEVT_RESULTCOPY</code>
+ or <code class="literal">PGEVT_RESULTDESTROY</code> events for this result or
+ results copied from it.
+ </p></dd><dt id="LIBPQ-PGEVT-RESULTCOPY"><span class="term"><code class="literal">PGEVT_RESULTCOPY</code></span> <a href="#LIBPQ-PGEVT-RESULTCOPY" class="id_link">#</a></dt><dd><p>
+ The result copy event is fired in response to
+ <a class="xref" href="libpq-misc.html#LIBPQ-PQCOPYRESULT"><code class="function">PQcopyResult</code></a>. This event will only be fired after
+ the copy is complete. Only event procedures that have
+ successfully handled the <code class="literal">PGEVT_RESULTCREATE</code>
+ or <code class="literal">PGEVT_RESULTCOPY</code> event for the source result
+ will receive <code class="literal">PGEVT_RESULTCOPY</code> events.
+
+</p><pre class="synopsis">
+typedef struct
+{
+ const PGresult *src;
+ PGresult *dest;
+} PGEventResultCopy;
+</pre><p>
+
+ When a <code class="literal">PGEVT_RESULTCOPY</code> event is received, the
+ <em class="parameter"><code>evtInfo</code></em> pointer should be cast to a
+ <code class="structname">PGEventResultCopy *</code>. The
+ <em class="parameter"><code>src</code></em> result is what was copied while the
+ <em class="parameter"><code>dest</code></em> result is the copy destination. This event
+ can be used to provide a deep copy of <code class="literal">instanceData</code>,
+ since <code class="literal">PQcopyResult</code> cannot do that. If an event
+ procedure fails (returns zero), that event procedure will be
+ ignored for the remaining lifetime of the new result; that is, it
+ will not receive <code class="literal">PGEVT_RESULTCOPY</code>
+ or <code class="literal">PGEVT_RESULTDESTROY</code> events for that result or
+ results copied from it.
+ </p></dd><dt id="LIBPQ-PGEVT-RESULTDESTROY"><span class="term"><code class="literal">PGEVT_RESULTDESTROY</code></span> <a href="#LIBPQ-PGEVT-RESULTDESTROY" class="id_link">#</a></dt><dd><p>
+ The result destroy event is fired in response to a
+ <a class="xref" href="libpq-exec.html#LIBPQ-PQCLEAR"><code class="function">PQclear</code></a>. It is the event procedure's
+ responsibility to properly clean up its event data as libpq has no
+ ability to manage this memory. Failure to clean up will lead
+ to memory leaks.
+
+</p><pre class="synopsis">
+typedef struct
+{
+ PGresult *result;
+} PGEventResultDestroy;
+</pre><p>
+
+ When a <code class="literal">PGEVT_RESULTDESTROY</code> event is received, the
+ <em class="parameter"><code>evtInfo</code></em> pointer should be cast to a
+ <code class="structname">PGEventResultDestroy *</code>. This event is fired
+ prior to <a class="xref" href="libpq-exec.html#LIBPQ-PQCLEAR"><code class="function">PQclear</code></a> performing any other cleanup.
+ The return value of the event procedure is ignored since there is no
+ way of indicating a failure from <a class="xref" href="libpq-exec.html#LIBPQ-PQCLEAR"><code class="function">PQclear</code></a>. Also,
+ an event procedure failure should not abort the process of cleaning up
+ unwanted memory.
+ </p></dd></dl></div></div><div class="sect2" id="LIBPQ-EVENTS-PROC"><div class="titlepage"><div><div><h3 class="title">34.14.2. Event Callback Procedure <a href="#LIBPQ-EVENTS-PROC" class="id_link">#</a></h3></div></div></div><div class="variablelist"><dl class="variablelist"><dt id="LIBPQ-PGEVENTPROC"><span class="term"><code class="literal">PGEventProc</code><a id="id-1.7.3.21.5.2.1.1.2" class="indexterm"></a></span> <a href="#LIBPQ-PGEVENTPROC" class="id_link">#</a></dt><dd><p>
+ <code class="literal">PGEventProc</code> is a typedef for a pointer to an
+ event procedure, that is, the user callback function that receives
+ events from libpq. The signature of an event procedure must be
+
+</p><pre class="synopsis">
+int eventproc(PGEventId evtId, void *evtInfo, void *passThrough)
+</pre><p>
+
+ The <em class="parameter"><code>evtId</code></em> parameter indicates which
+ <code class="literal">PGEVT</code> event occurred. The
+ <em class="parameter"><code>evtInfo</code></em> pointer must be cast to the appropriate
+ structure type to obtain further information about the event.
+ The <em class="parameter"><code>passThrough</code></em> parameter is the pointer
+ provided to <a class="xref" href="libpq-events.html#LIBPQ-PQREGISTEREVENTPROC"><code class="function">PQregisterEventProc</code></a> when the event
+ procedure was registered. The function should return a non-zero value
+ if it succeeds and zero if it fails.
+ </p><p>
+ A particular event procedure can be registered only once in any
+ <code class="structname">PGconn</code>. This is because the address of the procedure
+ is used as a lookup key to identify the associated instance data.
+ </p><div class="caution"><h3 class="title">Caution</h3><p>
+ On Windows, functions can have two different addresses: one visible
+ from outside a DLL and another visible from inside the DLL. One
+ should be careful that only one of these addresses is used with
+ <span class="application">libpq</span>'s event-procedure functions, else confusion will
+ result. The simplest rule for writing code that will work is to
+ ensure that event procedures are declared <code class="literal">static</code>. If the
+ procedure's address must be available outside its own source file,
+ expose a separate function to return the address.
+ </p></div></dd></dl></div></div><div class="sect2" id="LIBPQ-EVENTS-FUNCS"><div class="titlepage"><div><div><h3 class="title">34.14.3. Event Support Functions <a href="#LIBPQ-EVENTS-FUNCS" class="id_link">#</a></h3></div></div></div><div class="variablelist"><dl class="variablelist"><dt id="LIBPQ-PQREGISTEREVENTPROC"><span class="term"><code class="function">PQregisterEventProc</code><a id="id-1.7.3.21.6.2.1.1.2" class="indexterm"></a></span> <a href="#LIBPQ-PQREGISTEREVENTPROC" class="id_link">#</a></dt><dd><p>
+ Registers an event callback procedure with libpq.
+
+</p><pre class="synopsis">
+int PQregisterEventProc(PGconn *conn, PGEventProc proc,
+ const char *name, void *passThrough);
+</pre><p>
+ </p><p>
+ An event procedure must be registered once on each
+ <code class="structname">PGconn</code> you want to receive events about. There is no
+ limit, other than memory, on the number of event procedures that
+ can be registered with a connection. The function returns a non-zero
+ value if it succeeds and zero if it fails.
+ </p><p>
+ The <em class="parameter"><code>proc</code></em> argument will be called when a libpq
+ event is fired. Its memory address is also used to lookup
+ <code class="literal">instanceData</code>. The <em class="parameter"><code>name</code></em>
+ argument is used to refer to the event procedure in error messages.
+ This value cannot be <code class="symbol">NULL</code> or a zero-length string. The name string is
+ copied into the <code class="structname">PGconn</code>, so what is passed need not be
+ long-lived. The <em class="parameter"><code>passThrough</code></em> pointer is passed
+ to the <em class="parameter"><code>proc</code></em> whenever an event occurs. This
+ argument can be <code class="symbol">NULL</code>.
+ </p></dd><dt id="LIBPQ-PQSETINSTANCEDATA"><span class="term"><code class="function">PQsetInstanceData</code><a id="id-1.7.3.21.6.2.2.1.2" class="indexterm"></a></span> <a href="#LIBPQ-PQSETINSTANCEDATA" class="id_link">#</a></dt><dd><p>
+ Sets the connection <em class="parameter"><code>conn</code></em>'s <code class="literal">instanceData</code>
+ for procedure <em class="parameter"><code>proc</code></em> to <em class="parameter"><code>data</code></em>. This
+ returns non-zero for success and zero for failure. (Failure is
+ only possible if <em class="parameter"><code>proc</code></em> has not been properly
+ registered in <em class="parameter"><code>conn</code></em>.)
+
+</p><pre class="synopsis">
+int PQsetInstanceData(PGconn *conn, PGEventProc proc, void *data);
+</pre><p>
+ </p></dd><dt id="LIBPQ-PQINSTANCEDATA"><span class="term"><code class="function">PQinstanceData</code><a id="id-1.7.3.21.6.2.3.1.2" class="indexterm"></a></span> <a href="#LIBPQ-PQINSTANCEDATA" class="id_link">#</a></dt><dd><p>
+ Returns the
+ connection <em class="parameter"><code>conn</code></em>'s <code class="literal">instanceData</code>
+ associated with procedure <em class="parameter"><code>proc</code></em>,
+ or <code class="symbol">NULL</code> if there is none.
+
+</p><pre class="synopsis">
+void *PQinstanceData(const PGconn *conn, PGEventProc proc);
+</pre><p>
+ </p></dd><dt id="LIBPQ-PQRESULTSETINSTANCEDATA"><span class="term"><code class="function">PQresultSetInstanceData</code><a id="id-1.7.3.21.6.2.4.1.2" class="indexterm"></a></span> <a href="#LIBPQ-PQRESULTSETINSTANCEDATA" class="id_link">#</a></dt><dd><p>
+ Sets the result's <code class="literal">instanceData</code>
+ for <em class="parameter"><code>proc</code></em> to <em class="parameter"><code>data</code></em>. This returns
+ non-zero for success and zero for failure. (Failure is only
+ possible if <em class="parameter"><code>proc</code></em> has not been properly registered
+ in the result.)
+
+</p><pre class="synopsis">
+int PQresultSetInstanceData(PGresult *res, PGEventProc proc, void *data);
+</pre><p>
+ </p><p>
+ Beware that any storage represented by <em class="parameter"><code>data</code></em>
+ will not be accounted for by <a class="xref" href="libpq-misc.html#LIBPQ-PQRESULTMEMORYSIZE"><code class="function">PQresultMemorySize</code></a>,
+ unless it is allocated using <a class="xref" href="libpq-misc.html#LIBPQ-PQRESULTALLOC"><code class="function">PQresultAlloc</code></a>.
+ (Doing so is recommendable because it eliminates the need to free
+ such storage explicitly when the result is destroyed.)
+ </p></dd><dt id="LIBPQ-PQRESULTINSTANCEDATA"><span class="term"><code class="function">PQresultInstanceData</code><a id="id-1.7.3.21.6.2.5.1.2" class="indexterm"></a></span> <a href="#LIBPQ-PQRESULTINSTANCEDATA" class="id_link">#</a></dt><dd><p>
+ Returns the result's <code class="literal">instanceData</code> associated with <em class="parameter"><code>proc</code></em>, or <code class="symbol">NULL</code>
+ if there is none.
+
+</p><pre class="synopsis">
+void *PQresultInstanceData(const PGresult *res, PGEventProc proc);
+</pre><p>
+ </p></dd></dl></div></div><div class="sect2" id="LIBPQ-EVENTS-EXAMPLE"><div class="titlepage"><div><div><h3 class="title">34.14.4. Event Example <a href="#LIBPQ-EVENTS-EXAMPLE" class="id_link">#</a></h3></div></div></div><p>
+ Here is a skeleton example of managing private data associated with
+ libpq connections and results.
+ </p><pre class="programlisting">
+
+/* required header for libpq events (note: includes libpq-fe.h) */
+#include &lt;libpq-events.h&gt;
+
+/* The instanceData */
+typedef struct
+{
+ int n;
+ char *str;
+} mydata;
+
+/* PGEventProc */
+static int myEventProc(PGEventId evtId, void *evtInfo, void *passThrough);
+
+int
+main(void)
+{
+ mydata *data;
+ PGresult *res;
+ PGconn *conn =
+ PQconnectdb("dbname=postgres options=-csearch_path=");
+
+ if (PQstatus(conn) != CONNECTION_OK)
+ {
+ /* PQerrorMessage's result includes a trailing newline */
+ fprintf(stderr, "%s", PQerrorMessage(conn));
+ PQfinish(conn);
+ return 1;
+ }
+
+ /* called once on any connection that should receive events.
+ * Sends a PGEVT_REGISTER to myEventProc.
+ */
+ if (!PQregisterEventProc(conn, myEventProc, "mydata_proc", NULL))
+ {
+ fprintf(stderr, "Cannot register PGEventProc\n");
+ PQfinish(conn);
+ return 1;
+ }
+
+ /* conn instanceData is available */
+ data = PQinstanceData(conn, myEventProc);
+
+ /* Sends a PGEVT_RESULTCREATE to myEventProc */
+ res = PQexec(conn, "SELECT 1 + 1");
+
+ /* result instanceData is available */
+ data = PQresultInstanceData(res, myEventProc);
+
+ /* If PG_COPYRES_EVENTS is used, sends a PGEVT_RESULTCOPY to myEventProc */
+ res_copy = PQcopyResult(res, PG_COPYRES_TUPLES | PG_COPYRES_EVENTS);
+
+ /* result instanceData is available if PG_COPYRES_EVENTS was
+ * used during the PQcopyResult call.
+ */
+ data = PQresultInstanceData(res_copy, myEventProc);
+
+ /* Both clears send a PGEVT_RESULTDESTROY to myEventProc */
+ PQclear(res);
+ PQclear(res_copy);
+
+ /* Sends a PGEVT_CONNDESTROY to myEventProc */
+ PQfinish(conn);
+
+ return 0;
+}
+
+static int
+myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
+{
+ switch (evtId)
+ {
+ case PGEVT_REGISTER:
+ {
+ PGEventRegister *e = (PGEventRegister *)evtInfo;
+ mydata *data = get_mydata(e-&gt;conn);
+
+ /* associate app specific data with connection */
+ PQsetInstanceData(e-&gt;conn, myEventProc, data);
+ break;
+ }
+
+ case PGEVT_CONNRESET:
+ {
+ PGEventConnReset *e = (PGEventConnReset *)evtInfo;
+ mydata *data = PQinstanceData(e-&gt;conn, myEventProc);
+
+ if (data)
+ memset(data, 0, sizeof(mydata));
+ break;
+ }
+
+ case PGEVT_CONNDESTROY:
+ {
+ PGEventConnDestroy *e = (PGEventConnDestroy *)evtInfo;
+ mydata *data = PQinstanceData(e-&gt;conn, myEventProc);
+
+ /* free instance data because the conn is being destroyed */
+ if (data)
+ free_mydata(data);
+ break;
+ }
+
+ case PGEVT_RESULTCREATE:
+ {
+ PGEventResultCreate *e = (PGEventResultCreate *)evtInfo;
+ mydata *conn_data = PQinstanceData(e-&gt;conn, myEventProc);
+ mydata *res_data = dup_mydata(conn_data);
+
+ /* associate app specific data with result (copy it from conn) */
+ PQresultSetInstanceData(e-&gt;result, myEventProc, res_data);
+ break;
+ }
+
+ case PGEVT_RESULTCOPY:
+ {
+ PGEventResultCopy *e = (PGEventResultCopy *)evtInfo;
+ mydata *src_data = PQresultInstanceData(e-&gt;src, myEventProc);
+ mydata *dest_data = dup_mydata(src_data);
+
+ /* associate app specific data with result (copy it from a result) */
+ PQresultSetInstanceData(e-&gt;dest, myEventProc, dest_data);
+ break;
+ }
+
+ case PGEVT_RESULTDESTROY:
+ {
+ PGEventResultDestroy *e = (PGEventResultDestroy *)evtInfo;
+ mydata *data = PQresultInstanceData(e-&gt;result, myEventProc);
+
+ /* free instance data because the result is being destroyed */
+ if (data)
+ free_mydata(data);
+ break;
+ }
+
+ /* unknown event ID, just return true. */
+ default:
+ break;
+ }
+
+ return true; /* event processing succeeded */
+}
+
+</pre></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="libpq-notice-processing.html" title="34.13. Notice Processing">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="libpq.html" title="Chapter 34. libpq — C Library">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="libpq-envars.html" title="34.15. Environment Variables">Next</a></td></tr><tr><td width="40%" align="left" valign="top">34.13. Notice Processing </td><td width="20%" align="center"><a accesskey="h" href="index.html" title="PostgreSQL 16.2 Documentation">Home</a></td><td width="40%" align="right" valign="top"> 34.15. Environment Variables</td></tr></table></div></body></html> \ No newline at end of file