libpqtypes - array.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  * array.c
  4  *   Type handler for the array data type.
  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 int
 15 pqt_put_array(PGtypeArgs *args)
 16 {
 17   int i;
 18   int hasnull=0;
 19   int ndims;
 20   int nitems;
 21   int arrsize;
 22   char *out;
 23   int lbound[MAXDIM];
 24   int dims[MAXDIM];
 25   PGarray *arr = va_arg(args->ap, PGarray *);
 26 
 27   PUTNULLCHK(args, arr);
 28 
 29   if (arr->ndims < 0)
 30     return args->errorf(args, "arr.ndims is invalid - %d", arr->ndims);
 31 
 32   /* auto configure when ndims is 0 to 1d array */
 33   if (arr->ndims == 0)
 34   {
 35     ndims = 1;
 36     dims[0] = arr->param->vcnt;
 37     lbound[0] = 1;
 38   }
 39   else
 40   {
 41     ndims = arr->ndims;
 42     memcpy(lbound, arr->lbound, sizeof(lbound));
 43     memcpy(dims, arr->dims, sizeof(dims));
 44   }
 45 
 46   nitems = 1;
 47   for (i=0; i < ndims; i++)
 48     nitems *= dims[i];
 49 
 50   /* make sure array is on the same page as the param */
 51   if (nitems != arr->param->vcnt)
 52     return args->errorf(args,
 53       "param element count %d is different than array's %d",
 54       arr->param->vcnt, nitems);
 55 
 56   /* header: ndims + hasnull + elemtype + ((dims + lbound) * ndims) */
 57   arrsize = 4 + 4 + 4 + (8 * ndims);
 58 
 59   /* compute data length, also  get the hasnull flag */
 60   for (i=0; i < arr->param->vcnt; i++)
 61   {
 62     if (arr->param->vals[i].format == 0)
 63       return args->errorf(args, "Cannot put array elements in text format");
 64 
 65     arrsize += 4;
 66     if (arr->param->vals[i].datal == NULL_LEN)
 67       hasnull = 1;
 68     else
 69       arrsize += arr->param->vals[i].datal;
 70   }
 71 
 72   /* make sure args->put.out is large enough */
 73   if (args->put.expandBuffer(args, arrsize) == -1)
 74     return -1;
 75 
 76   out = args->put.out;
 77 
 78   /* number od dimensions */
 79   pqt_buf_putint4(out, ndims);
 80   out += 4;
 81 
 82   /* array hasnull flag */
 83   pqt_buf_putint4(out, hasnull);
 84   out += 4;
 85 
 86   /* array element oid */
 87   pqt_buf_putint4(out, args->typhandler->typoid);
 88   out += 4;
 89 
 90   /* dims and lbound */
 91   for (i=0; i < ndims; i++)
 92   {
 93     pqt_buf_putint4(out, dims[i]);
 94     out += 4;
 95 
 96     pqt_buf_putint4(out, lbound[i]);
 97     out += 4;
 98   }
 99 
100   /* write the element lengths and data */
101   for (i=0; i < arr->param->vcnt; i++)
102   {
103     pqt_buf_putint4(out, arr->param->vals[i].datal);
104     out += 4;
105 
106     if (arr->param->vals[i].datal > 0)
107     {
108       memcpy(out, arr->param->vals[i].data, arr->param->vals[i].datal);
109       out += arr->param->vals[i].datal;
110     }
111   }
112 
113   return arrsize;
114 }
115 
116 int
117 pqt_get_array(PGtypeArgs *args)
118 {
119   int i,t;
120   int vlen;
121   int ntups;
122   int nattrs;
123   Oid elemoid;
124   DECLVALUE(args);
125   PGresult *res;
126   int first_tup;
127   PGarray *arr = va_arg(args->ap, PGarray *);
128 
129   CHKGETVALS(args, arr);
130 
131   if (args->format == TEXTFMT)
132     return args->errorf(args, "array does not support text results");
133 
134   /* number of dims */
135   arr->ndims = pqt_buf_getint4(value);
136   value += 4;
137 
138   /* skip NULL flag */
139   value += 4;
140 
141   /* check the element oid */
142   elemoid = (Oid)pqt_buf_getint4(value);
143   if (elemoid != args->typhandler->typoid)
144     return args->errorf(args,
145       "array element type %u is different than what server says %u",
146       args->typhandler->typoid, elemoid);
147   value += 4;
148 
149   /* arr dims and lbounds */
150   first_tup = 1;
151   for (i=0, ntups=1; i < arr->ndims; i++)
152   {
153     arr->dims[i] = pqt_buf_getint4(value);
154     value += 4;
155 
156     arr->lbound[i] = pqt_buf_getint4(value);
157     value += 4;
158 
159     ntups *= arr->dims[i];
160   }
161 
162   /* This means ndims is zero because the above loop never iterated. */
163   if (i == 0)
164     ntups = 0;
165 
166   /* numTuples is the number of array items
167    * and numAttributes is 1 for non-composites.
168    */
169   nattrs = (args->typhandler->nattrs > 0) ? args->typhandler->nattrs : 1;
170 
171   if (!(res = pqt_copyresult(args, nattrs)))
172     RERR_MEM(args);
173 
174   for (t=0; t < ntups; t++)
175   {
176     /* get the value len */
177     vlen = pqt_buf_getint4(value);
178     value += 4;
179 
180     /* Regular Array with 1 attr per tuple */
181     if (args->typhandler->nattrs == 0)
182     {
183       /* set the field value */
184       if (!PQsetvalue(res, t, 0, value, vlen))
185       {
186         PQclear(res);
187         return -1;
188       }
189 
190       if (vlen > 0)
191         value += vlen;
192 
193       continue;
194     }
195 
196     /* ------------------------
197      * COMPOSITE/RECORD
198      */
199 
200     /* NULL compsoite array item, fill in attrs with NULL */
201     if (vlen == NULL_LEN)
202     {
203       int x;
204 
205       for (x=0; x < nattrs; x++)
206       {
207         if (!PQsetvalue(res, t, x, NULL, NULL_LEN))
208         {
209           PQclear(res);
210           return -1;
211         }
212       }
213 
214       /* move on to next tuple, done here. */
215       continue;
216     }
217 
218     /* verify that server's attr count matches ours */
219     if (first_tup)
220     {
221       int attcnt = pqt_buf_getint4(value);
222 
223       /* watch for invalidation issues */
224       if (attcnt != nattrs)
225       {
226         PQclear(res);
227         return args->errorf(args,
228           "type handler attribute count is %d but server says it's %d",
229           args->typhandler->nattrs, attcnt);
230       }
231     }
232 
233     /* skip attr count */
234     value += 4;
235 
236     /* composite attributes (record columns) */
237     for (i=0; i < nattrs; i++)
238     {
239       /* watch for invalidation issues */
240       if (first_tup &&
241          (Oid) pqt_buf_getint4(value) != args->typhandler->attDescs[i].attoid)
242       {
243         Oid server_oid = (Oid) pqt_buf_getint4(value);
244 
245         args->errorf(args,
246           "type handler attribute OID is %u but server says it's %u",
247           args->typhandler->attDescs[i].attoid, server_oid);
248 
249         PQclear(res);
250         return -1;
251       }
252 
253       /* skip oid */
254       value += 4;
255 
256       /* get the value length */
257       vlen = pqt_buf_getint4(value);
258       value += 4;
259 
260       /* set the field value */
261       if (!PQsetvalue(res, t, i, value, vlen))
262       {
263         PQclear(res);
264         return -1;
265       }
266 
267       if (vlen > 0)
268         value += vlen;
269     }
270 
271     first_tup = 0;
272   }
273 
274   arr->res = res;
275   return 0;
276 }