libpqtypes - events.c

Home Page

  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 }