Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * libpq-events.c
4 : : * functions for supporting the libpq "events" API
5 : : *
6 : : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 : : * Portions Copyright (c) 1994, Regents of the University of California
8 : : *
9 : : *
10 : : * IDENTIFICATION
11 : : * src/interfaces/libpq/libpq-events.c
12 : : *
13 : : *-------------------------------------------------------------------------
14 : : */
15 : : #include "postgres_fe.h"
16 : :
17 : : #include "libpq-fe.h"
18 : : #include "libpq-int.h"
19 : :
20 : :
21 : : /*
22 : : * Registers an event proc with the given PGconn.
23 : : *
24 : : * The same proc can't be registered more than once in a PGconn. This
25 : : * restriction is required because we use the proc address to identify
26 : : * the event for purposes such as PQinstanceData().
27 : : *
28 : : * The name argument is used within error messages to aid in debugging.
29 : : * A name must be supplied, but it needn't be unique. The string is
30 : : * copied, so the passed value needn't be long-lived.
31 : : *
32 : : * The passThrough argument is an application specific pointer and can be set
33 : : * to NULL if not required. It is passed through to the event proc whenever
34 : : * the event proc is called, and is not otherwise touched by libpq.
35 : : *
36 : : * The function returns a non-zero if successful. If the function fails,
37 : : * zero is returned.
38 : : */
39 : : int
5688 tgl@sss.pgh.pa.us 40 :UBC 0 : PQregisterEventProc(PGconn *conn, PGEventProc proc,
41 : : const char *name, void *passThrough)
42 : : {
43 : : int i;
44 : : PGEventRegister regevt;
45 : :
46 [ # # # # : 0 : if (!proc || !conn || !name || !*name)
# # # # ]
2433 peter_e@gmx.net 47 : 0 : return false; /* bad arguments */
48 : :
5688 tgl@sss.pgh.pa.us 49 [ # # ]: 0 : for (i = 0; i < conn->nEvents; i++)
50 : : {
51 [ # # ]: 0 : if (conn->events[i].proc == proc)
2433 peter_e@gmx.net 52 : 0 : return false; /* already registered */
53 : : }
54 : :
5688 tgl@sss.pgh.pa.us 55 [ # # ]: 0 : if (conn->nEvents >= conn->eventArraySize)
56 : : {
57 : : PGEvent *e;
58 : : int newSize;
59 : :
60 [ # # ]: 0 : newSize = conn->eventArraySize ? conn->eventArraySize * 2 : 8;
61 [ # # ]: 0 : if (conn->events)
62 : 0 : e = (PGEvent *) realloc(conn->events, newSize * sizeof(PGEvent));
63 : : else
64 : 0 : e = (PGEvent *) malloc(newSize * sizeof(PGEvent));
65 : :
66 [ # # ]: 0 : if (!e)
2433 peter_e@gmx.net 67 : 0 : return false;
68 : :
5688 tgl@sss.pgh.pa.us 69 : 0 : conn->eventArraySize = newSize;
70 : 0 : conn->events = e;
71 : : }
72 : :
73 : 0 : conn->events[conn->nEvents].proc = proc;
74 : 0 : conn->events[conn->nEvents].name = strdup(name);
75 [ # # ]: 0 : if (!conn->events[conn->nEvents].name)
2433 peter_e@gmx.net 76 : 0 : return false;
5688 tgl@sss.pgh.pa.us 77 : 0 : conn->events[conn->nEvents].passThrough = passThrough;
78 : 0 : conn->events[conn->nEvents].data = NULL;
2433 peter_e@gmx.net 79 : 0 : conn->events[conn->nEvents].resultInitialized = false;
5688 tgl@sss.pgh.pa.us 80 : 0 : conn->nEvents++;
81 : :
82 : 0 : regevt.conn = conn;
83 [ # # ]: 0 : if (!proc(PGEVT_REGISTER, ®evt, passThrough))
84 : : {
85 : 0 : conn->nEvents--;
86 : 0 : free(conn->events[conn->nEvents].name);
2433 peter_e@gmx.net 87 : 0 : return false;
88 : : }
89 : :
90 : 0 : return true;
91 : : }
92 : :
93 : : /*
94 : : * Set some "instance data" for an event within a PGconn.
95 : : * Returns nonzero on success, zero on failure.
96 : : */
97 : : int
5688 tgl@sss.pgh.pa.us 98 : 0 : PQsetInstanceData(PGconn *conn, PGEventProc proc, void *data)
99 : : {
100 : : int i;
101 : :
102 [ # # # # ]: 0 : if (!conn || !proc)
2433 peter_e@gmx.net 103 : 0 : return false;
104 : :
5688 tgl@sss.pgh.pa.us 105 [ # # ]: 0 : for (i = 0; i < conn->nEvents; i++)
106 : : {
107 [ # # ]: 0 : if (conn->events[i].proc == proc)
108 : : {
109 : 0 : conn->events[i].data = data;
2433 peter_e@gmx.net 110 : 0 : return true;
111 : : }
112 : : }
113 : :
114 : 0 : return false;
115 : : }
116 : :
117 : : /*
118 : : * Obtain the "instance data", if any, for the event.
119 : : */
120 : : void *
5688 tgl@sss.pgh.pa.us 121 : 0 : PQinstanceData(const PGconn *conn, PGEventProc proc)
122 : : {
123 : : int i;
124 : :
125 [ # # # # ]: 0 : if (!conn || !proc)
126 : 0 : return NULL;
127 : :
128 [ # # ]: 0 : for (i = 0; i < conn->nEvents; i++)
129 : : {
130 [ # # ]: 0 : if (conn->events[i].proc == proc)
131 : 0 : return conn->events[i].data;
132 : : }
133 : :
134 : 0 : return NULL;
135 : : }
136 : :
137 : : /*
138 : : * Set some "instance data" for an event within a PGresult.
139 : : * Returns nonzero on success, zero on failure.
140 : : */
141 : : int
142 : 0 : PQresultSetInstanceData(PGresult *result, PGEventProc proc, void *data)
143 : : {
144 : : int i;
145 : :
146 [ # # # # ]: 0 : if (!result || !proc)
2433 peter_e@gmx.net 147 : 0 : return false;
148 : :
5688 tgl@sss.pgh.pa.us 149 [ # # ]: 0 : for (i = 0; i < result->nEvents; i++)
150 : : {
151 [ # # ]: 0 : if (result->events[i].proc == proc)
152 : : {
153 : 0 : result->events[i].data = data;
2433 peter_e@gmx.net 154 : 0 : return true;
155 : : }
156 : : }
157 : :
158 : 0 : return false;
159 : : }
160 : :
161 : : /*
162 : : * Obtain the "instance data", if any, for the event.
163 : : */
164 : : void *
5688 tgl@sss.pgh.pa.us 165 : 0 : PQresultInstanceData(const PGresult *result, PGEventProc proc)
166 : : {
167 : : int i;
168 : :
169 [ # # # # ]: 0 : if (!result || !proc)
170 : 0 : return NULL;
171 : :
172 [ # # ]: 0 : for (i = 0; i < result->nEvents; i++)
173 [ # # ]: 0 : if (result->events[i].proc == proc)
174 : 0 : return result->events[i].data;
175 : :
176 : 0 : return NULL;
177 : : }
178 : :
179 : : /*
180 : : * Fire RESULTCREATE events for an application-created PGresult.
181 : : *
182 : : * The conn argument can be NULL if event procedures won't use it.
183 : : */
184 : : int
5686 185 : 0 : PQfireResultCreateEvents(PGconn *conn, PGresult *res)
186 : : {
786 187 : 0 : int result = true;
188 : : int i;
189 : :
5686 190 [ # # ]: 0 : if (!res)
2433 peter_e@gmx.net 191 : 0 : return false;
192 : :
5686 tgl@sss.pgh.pa.us 193 [ # # ]: 0 : for (i = 0; i < res->nEvents; i++)
194 : : {
195 : : /* It's possible event was already fired, if so don't repeat it */
196 [ # # ]: 0 : if (!res->events[i].resultInitialized)
197 : : {
198 : : PGEventResultCreate evt;
199 : :
200 : 0 : evt.conn = conn;
201 : 0 : evt.result = res;
786 202 [ # # ]: 0 : if (res->events[i].proc(PGEVT_RESULTCREATE, &evt,
203 : 0 : res->events[i].passThrough))
204 : 0 : res->events[i].resultInitialized = true;
205 : : else
206 : 0 : result = false;
207 : : }
208 : : }
209 : :
210 : 0 : return result;
211 : : }
|