Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * libpq-events.c
4 : * functions for supporting the libpq "events" API
5 : *
6 : * Portions Copyright (c) 1996-2017, 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
40 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)
47 0 : return FALSE; /* bad arguments */
48 :
49 0 : for (i = 0; i < conn->nEvents; i++)
50 : {
51 0 : if (conn->events[i].proc == proc)
52 0 : return FALSE; /* already registered */
53 : }
54 :
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)
67 0 : return FALSE;
68 :
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)
76 0 : return FALSE;
77 0 : conn->events[conn->nEvents].passThrough = passThrough;
78 0 : conn->events[conn->nEvents].data = NULL;
79 0 : conn->events[conn->nEvents].resultInitialized = FALSE;
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);
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
98 0 : PQsetInstanceData(PGconn *conn, PGEventProc proc, void *data)
99 : {
100 : int i;
101 :
102 0 : if (!conn || !proc)
103 0 : return FALSE;
104 :
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;
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 *
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)
147 0 : return FALSE;
148 :
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;
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 *
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
185 0 : PQfireResultCreateEvents(PGconn *conn, PGresult *res)
186 : {
187 : int i;
188 :
189 0 : if (!res)
190 0 : return FALSE;
191 :
192 0 : for (i = 0; i < res->nEvents; i++)
193 : {
194 0 : if (!res->events[i].resultInitialized)
195 : {
196 : PGEventResultCreate evt;
197 :
198 0 : evt.conn = conn;
199 0 : evt.result = res;
200 0 : if (!res->events[i].proc(PGEVT_RESULTCREATE, &evt,
201 0 : res->events[i].passThrough))
202 0 : return FALSE;
203 :
204 0 : res->events[i].resultInitialized = TRUE;
205 : }
206 : }
207 :
208 0 : return TRUE;
209 : }
|