summaryrefslogtreecommitdiffstats
path: root/doc/src/sgml/html/libpq-events.html
blob: 4fff4529542878c41a6cc2d1990d370f292d2e8c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
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 15.7 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</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</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></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></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></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></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></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></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</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></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</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></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></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></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></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></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</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 15.7 Documentation">Home</a></td><td width="40%" align="right" valign="top"> 34.15. Environment Variables</td></tr></table></div></body></html>