libpqtypes - geo.c

Home Page

array.c
datetime.c
error.c
events.c
exec.c
geo.c
getaddrinfo.h
handler.c
libpqtypes-int.h
libpqtypes.h
misc.c
network.c
numerics.c
param.c
port.c
record.c
regression-test.c
spec.c
utils.c
varlena.c
  1 
  2 /*
  3  * geo.c
  4  *   Type handler for the geometric data types.
  5  *
  6  * Copyright (c) 2011 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 int text2point(PGpoint *pt, char *text, char **endptr);
 15 static int text2points(PGtypeArgs *args, PGpoint **pts, int *npts);
 16 static int bin2points(PGtypeArgs *args, char *valp, int ptcnt,
 17   PGpoint **pts, int *npts);
 18 static int putpoints(PGtypeArgs *args, int npts, PGpoint *pts,
 19   int is_path, int closed);
 20 
 21 int
 22 pqt_put_point(PGtypeArgs *args)
 23 {
 24   unsigned int *buf;
 25   PGpoint *pt = va_arg(args->ap, PGpoint *);
 26 
 27   PUTNULLCHK(args, pt);
 28 
 29   buf = (unsigned int *) args->put.out;
 30   pqt_swap8(buf,     &pt->x, 1);
 31   pqt_swap8(buf + 2, &pt->y, 1);
 32   return 16;
 33 }
 34 
 35 int
 36 pqt_get_point(PGtypeArgs *args)
 37 {
 38   DECLVALUE(args);
 39   PGpoint *pt = va_arg(args->ap, PGpoint *);
 40 
 41   CHKGETVALS(args, pt);
 42 
 43   if (args->format == TEXTFMT)
 44   {
 45     if (!text2point(pt, value, NULL))
 46       RERR_STR2INT(args);
 47 
 48     return 0;
 49   }
 50 
 51   pqt_swap8(&pt->x, (unsigned int *) value, 0);
 52   pqt_swap8(&pt->y, ((unsigned int *) (value)) + 2, 0);
 53   return 0;
 54 }
 55 
 56 int
 57 pqt_put_lseg(PGtypeArgs *args)
 58 {
 59   unsigned int *buf;
 60   PGlseg *lseg = va_arg(args->ap, PGlseg *);
 61 
 62   PUTNULLCHK(args, lseg);
 63 
 64   buf = (unsigned int *) args->put.out;
 65   pqt_swap8(buf,     &lseg->pts[0].x, 1);
 66   pqt_swap8(buf + 2, &lseg->pts[0].y, 1);
 67   pqt_swap8(buf + 4, &lseg->pts[1].x, 1);
 68   pqt_swap8(buf + 6, &lseg->pts[1].y, 1);
 69   return 32;
 70 }
 71 
 72 int
 73 pqt_get_lseg(PGtypeArgs *args)
 74 {
 75   DECLVALUE(args);
 76   unsigned int *v;
 77   PGlseg *lseg = va_arg(args->ap, PGlseg *);
 78 
 79   CHKGETVALS(args, lseg);
 80 
 81   if (args->format == TEXTFMT)
 82   {
 83     PGpoint *pts = (PGpoint *)lseg;
 84 
 85     if (*value++ != '[' ||
 86        !text2point(pts, value, &value) ||
 87        *value++ != ',' ||
 88        !text2point(pts + 1, value, &value) ||
 89        *value != ']')
 90       RERR_STR2INT(args);
 91 
 92     return 0;
 93   }
 94 
 95   v = (unsigned int *) value;
 96   pqt_swap8(&lseg->pts[0].x, v, 0);
 97   pqt_swap8(&lseg->pts[0].y, v + 2, 0);
 98   pqt_swap8(&lseg->pts[1].x, v + 4, 0);
 99   pqt_swap8(&lseg->pts[1].y, v + 6, 0);
100   return 0;
101 }
102 
103 int
104 pqt_put_box(PGtypeArgs *args)
105 {
106   unsigned int *buf;
107   PGbox *box = va_arg(args->ap, PGbox *);
108 
109   PUTNULLCHK(args, box);
110 
111   buf = (unsigned int *) args->put.out;
112   pqt_swap8(buf,     &box->high.x, 1);
113   pqt_swap8(buf + 2, &box->high.y, 1);
114   pqt_swap8(buf + 4, &box->low.x,  1);
115   pqt_swap8(buf + 6, &box->low.y,  1);
116   return 32;
117 }
118 
119 int
120 pqt_get_box(PGtypeArgs *args)
121 {
122   DECLVALUE(args);
123   unsigned int *v;
124   PGbox *box = va_arg(args->ap, PGbox *);
125 
126   CHKGETVALS(args, box);
127 
128   if (args->format == TEXTFMT)
129   {
130     PGpoint *pts = (PGpoint *)box;
131 
132     if (!text2point(pts, value, &value) ||
133        *value++ != ',' ||
134        !text2point(pts + 1, value, NULL))
135       RERR_STR2INT(args);
136 
137     return 0;
138   }
139 
140   v = (unsigned int *) value;
141   pqt_swap8(&box->high.x, v, 0);
142   pqt_swap8(&box->high.y, v + 2, 0);
143   pqt_swap8(&box->low.x,  v + 4, 0);
144   pqt_swap8(&box->low.y,  v + 6, 0);
145   return 0;
146 }
147 
148 int
149 pqt_put_circle(PGtypeArgs *args)
150 {
151   unsigned int *buf;
152   PGcircle *circle = va_arg(args->ap, PGcircle *);
153 
154   PUTNULLCHK(args, circle);
155 
156   buf = (unsigned int *) args->put.out;
157   pqt_swap8(buf,     &circle->center.x, 1);
158   pqt_swap8(buf + 2, &circle->center.y, 1);
159   pqt_swap8(buf + 4, &circle->radius,   1);
160   return 24;
161 }
162 
163 int
164 pqt_get_circle(PGtypeArgs *args)
165 {
166   DECLVALUE(args);
167   unsigned int *v;
168   PGcircle *circle = va_arg(args->ap, PGcircle *);
169 
170   CHKGETVALS(args, circle);
171 
172   if (args->format == TEXTFMT)
173   {
174     if (*value++ != '<' ||
175        !text2point((PGpoint *)circle, value, &value) ||
176        *value++ != ',' ||
177        !pqt_text_to_float8(&circle->radius, value, &value) ||
178        *value != '>')
179       RERR_STR2INT(args);
180 
181     return 0;
182   }
183 
184   v = (unsigned int *) value;
185   pqt_swap8(&circle->center.x, v, 0);
186   pqt_swap8(&circle->center.y, v + 2, 0);
187   pqt_swap8(&circle->radius,   v + 4, 0);
188   return 0;
189 }
190 
191 int
192 pqt_put_path(PGtypeArgs *args)
193 {
194   PGpath *path = va_arg(args->ap, PGpath *);
195   PUTNULLCHK(args, path);
196   return putpoints(args, path->npts, path->pts, 1, path->closed ? 1 : 0);
197 }
198 
199 int
200 pqt_get_path(PGtypeArgs *args)
201 {
202   DECLVALUE(args);
203   PGpath *path = va_arg(args->ap, PGpath *);
204 
205   CHKGETVALS(args, path);
206 
207   if (args->format == TEXTFMT)
208   {
209     path->closed = *value == '(' ? 1 : 0;
210     return text2points(args, &path->pts, &path->npts);
211   }
212 
213   path->closed = *value ? 1 : 0;
214   value++;
215 
216   return bin2points(args,
217     value + sizeof(int), /* beginning of point array */
218     pqt_buf_getint4(value),  /* number of points */
219     &path->pts, &path->npts);
220 }
221 
222 int
223 pqt_put_polygon(PGtypeArgs *args)
224 {
225   PGpolygon *polygon = va_arg(args->ap, PGpolygon *);
226   PUTNULLCHK(args, polygon);
227   return putpoints(args, polygon->npts, polygon->pts, 0, 0);
228 }
229 
230 int
231 pqt_get_polygon(PGtypeArgs *args)
232 {
233   DECLVALUE(args);
234   PGpolygon *polygon = va_arg(args->ap, PGpolygon *);
235 
236   CHKGETVALS(args, polygon);
237 
238   if (args->format == TEXTFMT)
239     return text2points(args, &polygon->pts, &polygon->npts);
240 
241   return bin2points(args,
242     value + sizeof(int), /* beginning of point array */
243     pqt_buf_getint4(value),  /* number of points */
244     &polygon->pts,
245     &polygon->npts);
246 }
247 
248 
249 static int
250 putpoints(PGtypeArgs *args, int npts, PGpoint *pts,
251   int is_path, int closed)
252 {
253   int i;
254   int datal;
255   int hdr = (int) sizeof(int);
256   char *out;
257 
258   /* pts is for a path, include 1 byte open/closed flag */
259   if (is_path)
260     hdr++;
261 
262   /* length of binary formated path */
263   datal = (npts * sizeof(PGpoint)) + hdr;
264 
265   /* make sure out is large enough */
266   if (args->put.expandBuffer(args, datal) == -1)
267     return -1;
268 
269   out = args->put.out;
270   if (is_path)
271     *out++ = closed ? 1 : 0; /* path open/closed flag */
272 
273   /* write the number of points as an int32 */
274   pqt_buf_putint4(out, npts);
275   out += 4;
276 
277   /* assign points to the data 'out' buffer */
278   for (i=0; i < npts; i++)
279   {
280     pqt_swap8(out, &pts[i].x, 1);
281     out += sizeof(double);
282 
283     pqt_swap8(out, &pts[i].y, 1);
284     out += sizeof(double);
285   }
286 
287   return datal;
288 }
289 
290 static int
291 text2points(PGtypeArgs *args, PGpoint **pts, int *npts)
292 {
293   DECLVALUE(args);
294   char *s;
295   int cnt = 0;
296   PGpoint *p = NULL;
297 
298   *pts = NULL;
299   *npts = 0;
300 
301   if (*value != '(' && *value != '[')
302     RERR(args, "malformed point array");
303 
304   /* get the number of points by counting the '(' */
305   for (s=value+1; *s; s++)
306   {
307     if (*s == '(')
308     {
309       if (!(s = strchr(s, ')'))) /* skip point contents */
310         break;
311       cnt++;
312     }
313   }
314 
315   if (cnt == 0)
316     return 0; /* empty point list */
317 
318   p = (PGpoint *) PQresultAlloc((PGresult *) args->get.result,
319     cnt * sizeof(PGpoint));
320   if (!p)
321     RERR_MEM(args);
322 
323   for (cnt=0; *++value; )
324   {
325     if (!text2point(&p[cnt++], value, &value))
326       RERR_STR2INT(args);
327 
328     /* done */
329     if (*value != ',')
330       break;
331   }
332 
333   *pts = p;
334   *npts = cnt;
335   return 0;
336 }
337 
338 static int
339 bin2points(PGtypeArgs *args, char *valp, int ptcnt,
340   PGpoint **pts, int *npts)
341 {
342   int i;
343   PGpoint *p;
344 
345   *pts = NULL;
346   *npts = 0;
347 
348   if (ptcnt == 0)
349     return 0;
350 
351   p = (PGpoint *) PQresultAlloc((PGresult *) args->get.result,
352     ptcnt * sizeof(PGpoint));
353 
354   if (!p)
355     RERR_MEM(args);
356 
357   for (i=0; i < ptcnt; i++)
358   {
359     pqt_swap8(&p[i].x, valp, 0);
360     valp += sizeof(double);
361 
362     pqt_swap8(&p[i].y, valp, 0);
363     valp += sizeof(double);
364   }
365 
366   *pts = p;
367   *npts = ptcnt;
368   return 0;
369 }
370 
371 static int
372 text2point(PGpoint *pt, char *text, char **endptr)
373 {
374   if (*text++ != '(')
375     return 0;
376 
377   if (!pqt_text_to_float8(&pt->x, text, &text) || *text++ != ',')
378     return 0;
379 
380   if (!pqt_text_to_float8(&pt->y, text, &text) || *text++ != ')')
381     return 0;
382 
383   if (endptr)
384     *endptr = text;
385   return 1;
386 }