1 2 /* 3 * events.c 4 * The libpq PGEventProc implementation. 5 * 6 * Copyright (c) 2009 eSilo, LLC. All rights reserved. 7 * This is free software; see the source for copying conditions. There is 8 * NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR 9 * PURPOSE. 10 */ 11 12 #include "libpqtypes-int.h" 13 14 static PGtypeData * 15 allocTypeData(PGconn *conn); 16 17 static void 18 freeTypeData(PGtypeData *typeData); 19 20 static int 21 expandRegisterTypes(PGregisterType **types, int count, int size); 22 23 int 24 PQtypesRegister(PGconn *conn) 25 { 26 return PQregisterEventProc(conn, pqt_eventproc, "pqtypes", NULL); 27 } 28 29 int 30 pqt_eventproc(PGEventId id, void *info, void *passThrough) 31 { 32 switch (id) 33 { 34 case PGEVT_REGISTER: 35 { 36 PGEventRegister *e = (PGEventRegister *) info; 37 void *data = allocTypeData(e->conn); 38 if (!data) 39 return FALSE; 40 PQsetInstanceData((PGconn *) e->conn, pqt_eventproc, data); 41 break; 42 } 43 44 case PGEVT_CONNRESET: 45 { 46 int i, hcnt; 47 int udt_count = 0; 48 int udt_size = 0; 49 int comp_count = 0; 50 int comp_size = 0; 51 PGregisterType *udt_types = NULL; 52 PGregisterType *comp_types = NULL; 53 PGtypeHandler *handlers; 54 PGEventConnReset *e = (PGEventConnReset *) info; 55 PGtypeData *connData = (PGtypeData *) PQinstanceData( 56 e->conn, pqt_eventproc); 57 58 if (!connData) 59 break; /* ignore this */ 60 61 /* Have to re-register the handlers to help avoid invalidation issues. 62 * Save off the handlers and set the conn's type handlers to NULL. 63 */ 64 hcnt = connData->typhcnt; 65 handlers = connData->typhandlers; 66 connData->typhcnt = 0; 67 connData->typhandlers = NULL; 68 69 /* re-register type handlers. It is entirely possible that a register 70 * will fail. This is most likely due to a previously registered type 71 * that no longer exists in the backend (corner case). We silently 72 * ignore these and let putf/getf alert the user ... "no such type". 73 * 74 * To avoid issuing register calls to the backend one-by-one, which 75 * has round trip performance problems, we group user-defined types 76 * and compsoites together. They are registered post-loop in single 77 * register calls. 78 */ 79 for (i=0; i < hcnt; i++) 80 { 81 switch(handlers[i].regtype) 82 { 83 /* No need to group sub classes since they don't communicate 84 * with the backend. 85 */ 86 case PQT_REGTYPE_SUBCLASS: 87 { 88 PGregisterType rt; 89 rt.typname = handlers[i].orig_typname; 90 rt.typput = handlers[i].orig_typput; 91 rt.typget = handlers[i].orig_typget; 92 (void) PQregisterSubClasses(e->conn, &rt, 1); 93 break; 94 } 95 96 case PQT_REGTYPE_USERDEFINED: 97 { 98 udt_size = expandRegisterTypes(&udt_types, udt_count, udt_size); 99 if (udt_size == -1) 100 { 101 if (udt_types) 102 free(udt_types); 103 104 if (comp_types) 105 free(comp_types); 106 107 pqt_freehandlers(handlers, hcnt); 108 return FALSE; 109 } 110 111 udt_types[udt_count].typname = handlers[i].orig_typname; 112 udt_types[udt_count].typput = handlers[i].orig_typput; 113 udt_types[udt_count++].typget = handlers[i].orig_typget; 114 break; 115 } 116 117 case PQT_REGTYPE_COMPOSITE: 118 { 119 comp_size = expandRegisterTypes(&comp_types, comp_count, comp_size); 120 if (comp_size == -1) 121 { 122 if (udt_types) 123 free(udt_types); 124 125 if (comp_types) 126 free(comp_types); 127 128 pqt_freehandlers(handlers, hcnt); 129 return FALSE; 130 } 131 132 comp_types[comp_count++].typname = handlers[i].orig_typname; 133 break; 134 } 135 } 136 } 137 138 if (udt_count > 0) 139 { 140 (void) PQregisterUserDefinedTypes(e->conn, udt_types, udt_count); 141 free(udt_types); 142 } 143 144 if (comp_count > 0) 145 { 146 (void) PQregisterComposites(e->conn, comp_types, comp_count); 147 free(comp_types); 148 } 149 150 /* free the old conn's handler list */ 151 pqt_freehandlers(handlers, hcnt); 152 break; 153 } 154 155 case PGEVT_CONNDESTROY: 156 { 157 PGEventConnDestroy *e = (PGEventConnDestroy *) info; 158 freeTypeData((PGtypeData *) PQinstanceData(e->conn, pqt_eventproc)); 159 break; 160 } 161 162 case PGEVT_RESULTCREATE: 163 { 164 PGtypeData *resData; 165 PGEventResultCreate *e = (PGEventResultCreate *) info; 166 PGtypeData *connData = (PGtypeData *) PQinstanceData( 167 e->conn, pqt_eventproc); 168 169 if (!connData || !(resData = allocTypeData(e->conn))) 170 return FALSE; 171 172 /* copy type handlers from PGconn's typeData */ 173 if (connData->typhcnt > 0) 174 { 175 resData->typhandlers = pqt_duphandlers( 176 connData->typhandlers, connData->typhcnt); 177 178 if (resData->typhandlers) 179 resData->typhcnt = connData->typhcnt; 180 } 181 182 /* copy type specs from PGconn's typeData */ 183 if (connData->typspeccnt > 0) 184 { 185 resData->typspecs = pqt_dupspecs( 186 connData->typspecs, connData->typspeccnt); 187 188 if (resData->typspecs) 189 resData->typspeccnt = connData->typspeccnt; 190 } 191 192 PQresultSetInstanceData((PGresult *) e->result, pqt_eventproc, resData); 193 break; 194 } 195 196 case PGEVT_RESULTCOPY: 197 { 198 PGtypeData *destData; 199 PGEventResultCopy *e = (PGEventResultCopy *) info; 200 PGtypeData *srcData = (PGtypeData *) PQresultInstanceData( 201 e->src, pqt_eventproc); 202 203 if (!srcData || !(destData = allocTypeData(NULL))) 204 return FALSE; 205 206 memcpy(&destData->fmtinfo, &srcData->fmtinfo, sizeof(PGtypeFormatInfo)); 207 208 /* copy type handlers from PGresult's typeData */ 209 if (srcData->typhcnt > 0) 210 { 211 destData->typhandlers = pqt_duphandlers( 212 srcData->typhandlers, srcData->typhcnt); 213 214 if (destData->typhandlers) 215 destData->typhcnt = srcData->typhcnt; 216 } 217 218 /* copy type specs from PGresult's typeData */ 219 if (srcData->typspeccnt > 0) 220 { 221 destData->typspecs = pqt_dupspecs( 222 srcData->typspecs, srcData->typspeccnt); 223 224 if (destData->typspecs) 225 destData->typspeccnt = srcData->typspeccnt; 226 } 227 228 PQresultSetInstanceData(e->dest, pqt_eventproc, destData); 229 break; 230 } 231 232 case PGEVT_RESULTDESTROY: 233 { 234 PGEventResultDestroy *e = (PGEventResultDestroy *) info; 235 freeTypeData((PGtypeData *) PQresultInstanceData( 236 e->result, pqt_eventproc)); 237 break; 238 } 239 } 240 241 return TRUE; 242 } 243 244 static PGtypeData * 245 allocTypeData(PGconn *conn) 246 { 247 PGtypeData *typeData = (PGtypeData *) malloc(sizeof(PGtypeData)); 248 249 if (typeData) 250 { 251 memset(typeData, 0, sizeof(PGtypeData)); 252 253 /* get type formatting info from conn */ 254 if (conn) 255 pqt_getfmtinfo(conn, &typeData->fmtinfo); 256 } 257 258 return typeData; 259 } 260 261 static void 262 freeTypeData(PGtypeData *typeData) 263 { 264 if (typeData) 265 { 266 pqt_freehandlers(typeData->typhandlers, typeData->typhcnt); 267 pqt_freespecs(typeData->typspecs, typeData->typspeccnt); 268 free(typeData); 269 } 270 } 271 272 static int 273 expandRegisterTypes(PGregisterType **types, int count, int size) 274 { 275 if (count == size) 276 { 277 void *p; 278 279 size = size ? size * 2 : 4; 280 281 p = pqt_realloc(*types, size * sizeof(PGregisterType)); 282 if (!p) 283 return -1; 284 285 *types = (PGregisterType *) p; 286 } 287 288 return size; 289 } |