1 /*-------------------------------------------------------------------------
2 *
3 * libpq-events.c
4 * functions for supporting the libpq "events" API
5 *
6 * Portions Copyright (c) 1996-2016, 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
PQregisterEventProc(PGconn * conn,PGEventProc proc,const char * name,void * passThrough)40 PQregisterEventProc(PGconn *conn, PGEventProc proc,
41 const char *name, void *passThrough)
42 {
43 int i;
44 PGEventRegister regevt;
45
46 if (!proc || !conn || !name || !*name)
47 return FALSE; /* bad arguments */
48
49 for (i = 0; i < conn->nEvents; i++)
50 {
51 if (conn->events[i].proc == proc)
52 return FALSE; /* already registered */
53 }
54
55 if (conn->nEvents >= conn->eventArraySize)
56 {
57 PGEvent *e;
58 int newSize;
59
60 newSize = conn->eventArraySize ? conn->eventArraySize * 2 : 8;
61 if (conn->events)
62 e = (PGEvent *) realloc(conn->events, newSize * sizeof(PGEvent));
63 else
64 e = (PGEvent *) malloc(newSize * sizeof(PGEvent));
65
66 if (!e)
67 return FALSE;
68
69 conn->eventArraySize = newSize;
70 conn->events = e;
71 }
72
73 conn->events[conn->nEvents].proc = proc;
74 conn->events[conn->nEvents].name = strdup(name);
75 if (!conn->events[conn->nEvents].name)
76 return FALSE;
77 conn->events[conn->nEvents].passThrough = passThrough;
78 conn->events[conn->nEvents].data = NULL;
79 conn->events[conn->nEvents].resultInitialized = FALSE;
80 conn->nEvents++;
81
82 regevt.conn = conn;
83 if (!proc(PGEVT_REGISTER, ®evt, passThrough))
84 {
85 conn->nEvents--;
86 free(conn->events[conn->nEvents].name);
87 return FALSE;
88 }
89
90 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
PQsetInstanceData(PGconn * conn,PGEventProc proc,void * data)98 PQsetInstanceData(PGconn *conn, PGEventProc proc, void *data)
99 {
100 int i;
101
102 if (!conn || !proc)
103 return FALSE;
104
105 for (i = 0; i < conn->nEvents; i++)
106 {
107 if (conn->events[i].proc == proc)
108 {
109 conn->events[i].data = data;
110 return TRUE;
111 }
112 }
113
114 return FALSE;
115 }
116
117 /*
118 * Obtain the "instance data", if any, for the event.
119 */
120 void *
PQinstanceData(const PGconn * conn,PGEventProc proc)121 PQinstanceData(const PGconn *conn, PGEventProc proc)
122 {
123 int i;
124
125 if (!conn || !proc)
126 return NULL;
127
128 for (i = 0; i < conn->nEvents; i++)
129 {
130 if (conn->events[i].proc == proc)
131 return conn->events[i].data;
132 }
133
134 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
PQresultSetInstanceData(PGresult * result,PGEventProc proc,void * data)142 PQresultSetInstanceData(PGresult *result, PGEventProc proc, void *data)
143 {
144 int i;
145
146 if (!result || !proc)
147 return FALSE;
148
149 for (i = 0; i < result->nEvents; i++)
150 {
151 if (result->events[i].proc == proc)
152 {
153 result->events[i].data = data;
154 return TRUE;
155 }
156 }
157
158 return FALSE;
159 }
160
161 /*
162 * Obtain the "instance data", if any, for the event.
163 */
164 void *
PQresultInstanceData(const PGresult * result,PGEventProc proc)165 PQresultInstanceData(const PGresult *result, PGEventProc proc)
166 {
167 int i;
168
169 if (!result || !proc)
170 return NULL;
171
172 for (i = 0; i < result->nEvents; i++)
173 if (result->events[i].proc == proc)
174 return result->events[i].data;
175
176 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
PQfireResultCreateEvents(PGconn * conn,PGresult * res)185 PQfireResultCreateEvents(PGconn *conn, PGresult *res)
186 {
187 int i;
188
189 if (!res)
190 return FALSE;
191
192 for (i = 0; i < res->nEvents; i++)
193 {
194 if (!res->events[i].resultInitialized)
195 {
196 PGEventResultCreate evt;
197
198 evt.conn = conn;
199 evt.result = res;
200 if (!res->events[i].proc(PGEVT_RESULTCREATE, &evt,
201 res->events[i].passThrough))
202 return FALSE;
203
204 res->events[i].resultInitialized = TRUE;
205 }
206 }
207
208 return TRUE;
209 }
210