]> begriffs open source - ai-pg/blob - full-docs/txt/libpq-events.txt
Convert HTML docs to more streamlined TXT
[ai-pg] / full-docs / txt / libpq-events.txt
1
2 32.14. Event System #
3
4    32.14.1. Event Types
5    32.14.2. Event Callback Procedure
6    32.14.3. Event Support Functions
7    32.14.4. Event Example
8
9    libpq's event system is designed to notify registered event handlers
10    about interesting libpq events, such as the creation or destruction of
11    PGconn and PGresult objects. A principal use case is that this allows
12    applications to associate their own data with a PGconn or PGresult and
13    ensure that that data is freed at an appropriate time.
14
15    Each registered event handler is associated with two pieces of data,
16    known to libpq only as opaque void * pointers. There is a pass-through
17    pointer that is provided by the application when the event handler is
18    registered with a PGconn. The pass-through pointer never changes for
19    the life of the PGconn and all PGresults generated from it; so if used,
20    it must point to long-lived data. In addition there is an instance data
21    pointer, which starts out NULL in every PGconn and PGresult. This
22    pointer can be manipulated using the PQinstanceData, PQsetInstanceData,
23    PQresultInstanceData and PQresultSetInstanceData functions. Note that
24    unlike the pass-through pointer, instance data of a PGconn is not
25    automatically inherited by PGresults created from it. libpq does not
26    know what pass-through and instance data pointers point to (if
27    anything) and will never attempt to free them — that is the
28    responsibility of the event handler.
29
30 32.14.1. Event Types #
31
32    The enum PGEventId names the types of events handled by the event
33    system. All its values have names beginning with PGEVT. For each event
34    type, there is a corresponding event info structure that carries the
35    parameters passed to the event handlers. The event types are:
36
37    PGEVT_REGISTER #
38           The register event occurs when PQregisterEventProc is called. It
39           is the ideal time to initialize any instanceData an event
40           procedure may need. Only one register event will be fired per
41           event handler per connection. If the event procedure fails
42           (returns zero), the registration is canceled.
43
44 typedef struct
45 {
46     PGconn *conn;
47 } PGEventRegister;
48
49           When a PGEVT_REGISTER event is received, the evtInfo pointer
50           should be cast to a PGEventRegister *. This structure contains a
51           PGconn that should be in the CONNECTION_OK status; guaranteed if
52           one calls PQregisterEventProc right after obtaining a good
53           PGconn. When returning a failure code, all cleanup must be
54           performed as no PGEVT_CONNDESTROY event will be sent.
55
56    PGEVT_CONNRESET #
57           The connection reset event is fired on completion of PQreset or
58           PQresetPoll. In both cases, the event is only fired if the reset
59           was successful. The return value of the event procedure is
60           ignored in PostgreSQL v15 and later. With earlier versions,
61           however, it's important to return success (nonzero) or the
62           connection will be aborted.
63
64 typedef struct
65 {
66     PGconn *conn;
67 } PGEventConnReset;
68
69           When a PGEVT_CONNRESET event is received, the evtInfo pointer
70           should be cast to a PGEventConnReset *. Although the contained
71           PGconn was just reset, all event data remains unchanged. This
72           event should be used to reset/reload/requery any associated
73           instanceData. Note that even if the event procedure fails to
74           process PGEVT_CONNRESET, it will still receive a
75           PGEVT_CONNDESTROY event when the connection is closed.
76
77    PGEVT_CONNDESTROY #
78           The connection destroy event is fired in response to PQfinish.
79           It is the event procedure's responsibility to properly clean up
80           its event data as libpq has no ability to manage this memory.
81           Failure to clean up will lead to memory leaks.
82
83 typedef struct
84 {
85     PGconn *conn;
86 } PGEventConnDestroy;
87
88           When a PGEVT_CONNDESTROY event is received, the evtInfo pointer
89           should be cast to a PGEventConnDestroy *. This event is fired
90           prior to PQfinish performing any other cleanup. The return value
91           of the event procedure is ignored since there is no way of
92           indicating a failure from PQfinish. Also, an event procedure
93           failure should not abort the process of cleaning up unwanted
94           memory.
95
96    PGEVT_RESULTCREATE #
97           The result creation event is fired in response to any query
98           execution function that generates a result, including
99           PQgetResult. This event will only be fired after the result has
100           been created successfully.
101
102 typedef struct
103 {
104     PGconn *conn;
105     PGresult *result;
106 } PGEventResultCreate;
107
108           When a PGEVT_RESULTCREATE event is received, the evtInfo pointer
109           should be cast to a PGEventResultCreate *. The conn is the
110           connection used to generate the result. This is the ideal place
111           to initialize any instanceData that needs to be associated with
112           the result. If an event procedure fails (returns zero), that
113           event procedure will be ignored for the remaining lifetime of
114           the result; that is, it will not receive PGEVT_RESULTCOPY or
115           PGEVT_RESULTDESTROY events for this result or results copied
116           from it.
117
118    PGEVT_RESULTCOPY #
119           The result copy event is fired in response to PQcopyResult. This
120           event will only be fired after the copy is complete. Only event
121           procedures that have successfully handled the PGEVT_RESULTCREATE
122           or PGEVT_RESULTCOPY event for the source result will receive
123           PGEVT_RESULTCOPY events.
124
125 typedef struct
126 {
127     const PGresult *src;
128     PGresult *dest;
129 } PGEventResultCopy;
130
131           When a PGEVT_RESULTCOPY event is received, the evtInfo pointer
132           should be cast to a PGEventResultCopy *. The src result is what
133           was copied while the dest result is the copy destination. This
134           event can be used to provide a deep copy of instanceData, since
135           PQcopyResult cannot do that. If an event procedure fails
136           (returns zero), that event procedure will be ignored for the
137           remaining lifetime of the new result; that is, it will not
138           receive PGEVT_RESULTCOPY or PGEVT_RESULTDESTROY events for that
139           result or results copied from it.
140
141    PGEVT_RESULTDESTROY #
142           The result destroy event is fired in response to a PQclear. It
143           is the event procedure's responsibility to properly clean up its
144           event data as libpq has no ability to manage this memory.
145           Failure to clean up will lead to memory leaks.
146
147 typedef struct
148 {
149     PGresult *result;
150 } PGEventResultDestroy;
151
152           When a PGEVT_RESULTDESTROY event is received, the evtInfo
153           pointer should be cast to a PGEventResultDestroy *. This event
154           is fired prior to PQclear performing any other cleanup. The
155           return value of the event procedure is ignored since there is no
156           way of indicating a failure from PQclear. Also, an event
157           procedure failure should not abort the process of cleaning up
158           unwanted memory.
159
160 32.14.2. Event Callback Procedure #
161
162    PGEventProc #
163           PGEventProc is a typedef for a pointer to an event procedure,
164           that is, the user callback function that receives events from
165           libpq. The signature of an event procedure must be
166
167 int eventproc(PGEventId evtId, void *evtInfo, void *passThrough)
168
169           The evtId parameter indicates which PGEVT event occurred. The
170           evtInfo pointer must be cast to the appropriate structure type
171           to obtain further information about the event. The passThrough
172           parameter is the pointer provided to PQregisterEventProc when
173           the event procedure was registered. The function should return a
174           non-zero value if it succeeds and zero if it fails.
175
176           A particular event procedure can be registered only once in any
177           PGconn. This is because the address of the procedure is used as
178           a lookup key to identify the associated instance data.
179
180 Caution
181
182           On Windows, functions can have two different addresses: one
183           visible from outside a DLL and another visible from inside the
184           DLL. One should be careful that only one of these addresses is
185           used with libpq's event-procedure functions, else confusion will
186           result. The simplest rule for writing code that will work is to
187           ensure that event procedures are declared static. If the
188           procedure's address must be available outside its own source
189           file, expose a separate function to return the address.
190
191 32.14.3. Event Support Functions #
192
193    PQregisterEventProc #
194           Registers an event callback procedure with libpq.
195
196 int PQregisterEventProc(PGconn *conn, PGEventProc proc,
197                         const char *name, void *passThrough);
198
199           An event procedure must be registered once on each PGconn you
200           want to receive events about. There is no limit, other than
201           memory, on the number of event procedures that can be registered
202           with a connection. The function returns a non-zero value if it
203           succeeds and zero if it fails.
204
205           The proc argument will be called when a libpq event is fired.
206           Its memory address is also used to lookup instanceData. The name
207           argument is used to refer to the event procedure in error
208           messages. This value cannot be NULL or a zero-length string. The
209           name string is copied into the PGconn, so what is passed need
210           not be long-lived. The passThrough pointer is passed to the proc
211           whenever an event occurs. This argument can be NULL.
212
213    PQsetInstanceData #
214           Sets the connection conn's instanceData for procedure proc to
215           data. This returns non-zero for success and zero for failure.
216           (Failure is only possible if proc has not been properly
217           registered in conn.)
218
219 int PQsetInstanceData(PGconn *conn, PGEventProc proc, void *data);
220
221    PQinstanceData #
222           Returns the connection conn's instanceData associated with
223           procedure proc, or NULL if there is none.
224
225 void *PQinstanceData(const PGconn *conn, PGEventProc proc);
226
227    PQresultSetInstanceData #
228           Sets the result's instanceData for proc to data. This returns
229           non-zero for success and zero for failure. (Failure is only
230           possible if proc has not been properly registered in the
231           result.)
232
233 int PQresultSetInstanceData(PGresult *res, PGEventProc proc, void *data);
234
235           Beware that any storage represented by data will not be
236           accounted for by PQresultMemorySize, unless it is allocated
237           using PQresultAlloc. (Doing so is recommendable because it
238           eliminates the need to free such storage explicitly when the
239           result is destroyed.)
240
241    PQresultInstanceData #
242           Returns the result's instanceData associated with proc, or NULL
243           if there is none.
244
245 void *PQresultInstanceData(const PGresult *res, PGEventProc proc);
246
247 32.14.4. Event Example #
248
249    Here is a skeleton example of managing private data associated with
250    libpq connections and results.
251
252 /* required header for libpq events (note: includes libpq-fe.h) */
253 #include <libpq-events.h>
254
255 /* The instanceData */
256 typedef struct
257 {
258     int n;
259     char *str;
260 } mydata;
261
262 /* PGEventProc */
263 static int myEventProc(PGEventId evtId, void *evtInfo, void *passThrough);
264
265 int
266 main(void)
267 {
268     mydata *data;
269     PGresult *res;
270     PGconn *conn =
271         PQconnectdb("dbname=postgres options=-csearch_path=");
272
273     if (PQstatus(conn) != CONNECTION_OK)
274     {
275         /* PQerrorMessage's result includes a trailing newline */
276         fprintf(stderr, "%s", PQerrorMessage(conn));
277         PQfinish(conn);
278         return 1;
279     }
280
281     /* called once on any connection that should receive events.
282      * Sends a PGEVT_REGISTER to myEventProc.
283      */
284     if (!PQregisterEventProc(conn, myEventProc, "mydata_proc", NULL))
285     {
286         fprintf(stderr, "Cannot register PGEventProc\n");
287         PQfinish(conn);
288         return 1;
289     }
290
291     /* conn instanceData is available */
292     data = PQinstanceData(conn, myEventProc);
293
294     /* Sends a PGEVT_RESULTCREATE to myEventProc */
295     res = PQexec(conn, "SELECT 1 + 1");
296
297     /* result instanceData is available */
298     data = PQresultInstanceData(res, myEventProc);
299
300     /* If PG_COPYRES_EVENTS is used, sends a PGEVT_RESULTCOPY to myEventProc */
301     res_copy = PQcopyResult(res, PG_COPYRES_TUPLES | PG_COPYRES_EVENTS);
302
303     /* result instanceData is available if PG_COPYRES_EVENTS was
304      * used during the PQcopyResult call.
305      */
306     data = PQresultInstanceData(res_copy, myEventProc);
307
308     /* Both clears send a PGEVT_RESULTDESTROY to myEventProc */
309     PQclear(res);
310     PQclear(res_copy);
311
312     /* Sends a PGEVT_CONNDESTROY to myEventProc */
313     PQfinish(conn);
314
315     return 0;
316 }
317
318 static int
319 myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
320 {
321     switch (evtId)
322     {
323         case PGEVT_REGISTER:
324         {
325             PGEventRegister *e = (PGEventRegister *)evtInfo;
326             mydata *data = get_mydata(e->conn);
327
328             /* associate app specific data with connection */
329             PQsetInstanceData(e->conn, myEventProc, data);
330             break;
331         }
332
333         case PGEVT_CONNRESET:
334         {
335             PGEventConnReset *e = (PGEventConnReset *)evtInfo;
336             mydata *data = PQinstanceData(e->conn, myEventProc);
337
338             if (data)
339               memset(data, 0, sizeof(mydata));
340             break;
341         }
342
343         case PGEVT_CONNDESTROY:
344         {
345             PGEventConnDestroy *e = (PGEventConnDestroy *)evtInfo;
346             mydata *data = PQinstanceData(e->conn, myEventProc);
347
348             /* free instance data because the conn is being destroyed */
349             if (data)
350               free_mydata(data);
351             break;
352         }
353
354         case PGEVT_RESULTCREATE:
355         {
356             PGEventResultCreate *e = (PGEventResultCreate *)evtInfo;
357             mydata *conn_data = PQinstanceData(e->conn, myEventProc);
358             mydata *res_data = dup_mydata(conn_data);
359
360             /* associate app specific data with result (copy it from conn) */
361             PQresultSetInstanceData(e->result, myEventProc, res_data);
362             break;
363         }
364
365         case PGEVT_RESULTCOPY:
366         {
367             PGEventResultCopy *e = (PGEventResultCopy *)evtInfo;
368             mydata *src_data = PQresultInstanceData(e->src, myEventProc);
369             mydata *dest_data = dup_mydata(src_data);
370
371             /* associate app specific data with result (copy it from a result) *
372 /
373             PQresultSetInstanceData(e->dest, myEventProc, dest_data);
374             break;
375         }
376
377         case PGEVT_RESULTDESTROY:
378         {
379             PGEventResultDestroy *e = (PGEventResultDestroy *)evtInfo;
380             mydata *data = PQresultInstanceData(e->result, myEventProc);
381
382             /* free instance data because the result is being destroyed */
383             if (data)
384               free_mydata(data);
385             break;
386         }
387
388         /* unknown event ID, just return true. */
389         default:
390             break;
391     }
392
393     return true; /* event processing succeeded */
394 }
395