PostgreSQL Source Code git master
libpq-events.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * libpq-events.c
4 * functions for supporting the libpq "events" API
5 *
6 * Portions Copyright (c) 1996-2025, 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 */
39int
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
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;
80 conn->nEvents++;
81
82 regevt.conn = conn;
83 if (!proc(PGEVT_REGISTER, &regevt, passThrough))
84 {
85 conn->nEvents--;
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 */
97int
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 */
120void *
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 */
141int
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 */
164void *
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 */
184int
186{
187 int result = true;
188 int i;
189
190 if (!res)
191 return false;
192
193 for (i = 0; i < res->nEvents; i++)
194 {
195 /* It's possible event was already fired, if so don't repeat it */
197 {
199
200 evt.conn = conn;
201 evt.result = res;
202 if (res->events[i].proc(PGEVT_RESULTCREATE, &evt,
204 res->events[i].resultInitialized = true;
205 else
206 result = false;
207 }
208 }
209
210 return result;
211}
#define realloc(a, b)
Definition: header.h:60
#define free(a)
Definition: header.h:65
#define malloc(a)
Definition: header.h:50
int i
Definition: isn.c:72
int PQresultSetInstanceData(PGresult *result, PGEventProc proc, void *data)
Definition: libpq-events.c:142
int PQfireResultCreateEvents(PGconn *conn, PGresult *res)
Definition: libpq-events.c:185
int PQregisterEventProc(PGconn *conn, PGEventProc proc, const char *name, void *passThrough)
Definition: libpq-events.c:40
void * PQresultInstanceData(const PGresult *result, PGEventProc proc)
Definition: libpq-events.c:165
int PQsetInstanceData(PGconn *conn, PGEventProc proc, void *data)
Definition: libpq-events.c:98
void * PQinstanceData(const PGconn *conn, PGEventProc proc)
Definition: libpq-events.c:121
@ PGEVT_RESULTCREATE
Definition: libpq-events.h:32
@ PGEVT_REGISTER
Definition: libpq-events.h:29
int(* PGEventProc)(PGEventId evtId, void *evtInfo, void *passThrough)
Definition: libpq-events.h:69
const void * data
e
Definition: preproc-init.c:82
PGconn * conn
Definition: streamutil.c:53
void * passThrough
Definition: libpq-int.h:167
char * name
Definition: libpq-int.h:166
void * data
Definition: libpq-int.h:168
PGEventProc proc
Definition: libpq-int.h:165
bool resultInitialized
Definition: libpq-int.h:169
int nEvents
Definition: libpq-int.h:449
int eventArraySize
Definition: libpq-int.h:450
PGEvent * events
Definition: libpq-int.h:448
int nEvents
Definition: libpq-int.h:193
PGEvent * events
Definition: libpq-int.h:192
const char * name