Age Owner 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-2023, 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
5317 tgl 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)
2062 peter_e 47 0 : return false; /* bad arguments */
48 :
5317 tgl 49 0 : for (i = 0; i < conn->nEvents; i++)
50 : {
51 0 : if (conn->events[i].proc == proc)
2062 peter_e 52 0 : return false; /* already registered */
53 : }
54 :
5317 tgl 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)
2062 peter_e 67 0 : return false;
68 :
5317 tgl 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)
2062 peter_e 76 0 : return false;
5317 tgl 77 0 : conn->events[conn->nEvents].passThrough = passThrough;
78 0 : conn->events[conn->nEvents].data = NULL;
2062 peter_e 79 0 : conn->events[conn->nEvents].resultInitialized = false;
5317 tgl 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);
2062 peter_e 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
5317 tgl 98 0 : PQsetInstanceData(PGconn *conn, PGEventProc proc, void *data)
99 : {
100 : int i;
101 :
102 0 : if (!conn || !proc)
2062 peter_e 103 0 : return false;
104 :
5317 tgl 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;
2062 peter_e 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 *
5317 tgl 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)
2062 peter_e 147 0 : return false;
148 :
5317 tgl 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;
2062 peter_e 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 *
5317 tgl 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
5315 185 0 : PQfireResultCreateEvents(PGconn *conn, PGresult *res)
186 : {
415 187 0 : int result = true;
188 : int i;
189 :
5315 190 0 : if (!res)
2062 peter_e 191 0 : return false;
192 :
5315 tgl 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;
415 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 : }
|