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 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 0 : int result = true; 188 : int i; 189 : 190 0 : if (!res) 191 0 : return false; 192 : 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; 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 : }