]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/arrayfuncs.c
d54a6847bd259656144cde2523f20f505ff7d7a4
[postgresql] / src / backend / utils / adt / arrayfuncs.c
1 /*-------------------------------------------------------------------------
2  *
3  * arrayfuncs.c
4  *        Special functions for arrays.
5  *
6  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.57 2000/06/13 07:35:03 tgl Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15
16 #include <ctype.h>
17
18 #include "postgres.h"
19
20 #include "catalog/catalog.h"
21 #include "catalog/pg_type.h"
22 #include "fmgr.h"
23 #include "libpq/be-fsstubs.h"
24 #include "libpq/libpq-fs.h"
25 #include "storage/fd.h"
26 #include "utils/array.h"
27 #include "utils/memutils.h"
28 #include "utils/syscache.h"
29
30 #define ASSGN    "="
31
32 /* An array has the following internal structure:
33  *        <nbytes>              - total number of bytes
34  *        <ndim>                - number of dimensions of the array
35  *        <flags>               - bit mask of flags
36  *        <dim>                 - size of each array axis
37  *        <dim_lower>   - lower boundary of each dimension
38  *        <actual data> - whatever is the stored data
39  */
40
41 /*-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-*/
42 static int      _ArrayCount(char *str, int *dim, int typdelim);
43 static char *_ReadArrayStr(char *arrayStr, int nitems, int ndim, int *dim,
44                           FmgrInfo *inputproc, Oid typelem, int32 typmod,
45                           char typdelim, int typlen, bool typbyval,
46                           char typalign, int *nbytes);
47
48 #ifdef LOARRAY
49 static char *_ReadLOArray(char *str, int *nbytes, int *fd, bool *chunkFlag,
50                          int ndim, int *dim, int baseSize);
51
52 #endif
53 static void _CopyArrayEls(char **values, char *p, int nitems, int typlen,
54                           char typalign, bool typbyval);
55 static void system_cache_lookup(Oid element_type, bool input, int *typlen,
56                                  bool *typbyval, char *typdelim, Oid *typelem, Oid *proc,
57                                         char *typalign);
58 static Datum _ArrayCast(char *value, bool byval, int len);
59
60 #ifdef LOARRAY
61 static char *_AdvanceBy1word(char *str, char **word);
62
63 #endif
64 static void _ArrayRange(int *st, int *endp, int bsize, char *destPtr,
65                         ArrayType *array, int from);
66 static int      _ArrayClipCount(int *stI, int *endpI, ArrayType *array);
67 static void _LOArrayRange(int *st, int *endp, int bsize, int srcfd,
68                           int destfd, ArrayType *array, int isSrcLO, bool *isNull);
69 static void _ReadArray(int *st, int *endp, int bsize, int srcfd, int destfd,
70                    ArrayType *array, int isDestLO, bool *isNull);
71 static int      ArrayCastAndSet(Datum src, bool typbyval, int typlen, char *dest);
72 static int      SanityCheckInput(int ndim, int n, int *dim, int *lb, int *indx);
73 static int      array_read(char *destptr, int eltsize, int nitems, char *srcptr);
74 static char *array_seek(char *ptr, int eltsize, int nitems);
75
76 /*---------------------------------------------------------------------
77  * array_in :
78  *                converts an array from the external format in "string" to
79  *                its internal format.
80  * return value :
81  *                the internal representation of the input array
82  *--------------------------------------------------------------------
83  */
84 Datum
85 array_in(PG_FUNCTION_ARGS)
86 {
87         char       *string = PG_GETARG_CSTRING(0); /* external form */
88         Oid                     element_type = PG_GETARG_OID(1); /* type of an array element */
89         int32           typmod = PG_GETARG_INT32(2); /* typmod for array elements */
90         int                     typlen;
91         bool            typbyval,
92                                 done;
93         char            typdelim;
94         Oid                     typinput;
95         Oid                     typelem;
96         char       *string_save,
97                            *p,
98                            *q,
99                            *r;
100         FmgrInfo        inputproc;
101         int                     i,
102                                 nitems;
103         int32           nbytes;
104         char       *dataPtr;
105         ArrayType  *retval;
106         int                     ndim,
107                                 dim[MAXDIM],
108                                 lBound[MAXDIM];
109         char            typalign;
110
111         system_cache_lookup(element_type, true, &typlen, &typbyval, &typdelim,
112                                                 &typelem, &typinput, &typalign);
113
114         fmgr_info(typinput, &inputproc);
115
116         string_save = (char *) palloc(strlen(string) + 3);
117         strcpy(string_save, string);
118
119         /* --- read array dimensions  ---------- */
120         p = q = string_save;
121         done = false;
122         for (ndim = 0; !done;)
123         {
124                 while (isspace(*p))
125                         p++;
126                 if (*p == '[')
127                 {
128                         p++;
129                         if ((r = (char *) strchr(p, ':')) == (char *) NULL)
130                                 lBound[ndim] = 1;
131                         else
132                         {
133                                 *r = '\0';
134                                 lBound[ndim] = atoi(p);
135                                 p = r + 1;
136                         }
137                         for (q = p; isdigit(*q); q++);
138                         if (*q != ']')
139                                 elog(ERROR, "array_in: missing ']' in array declaration");
140                         *q = '\0';
141                         dim[ndim] = atoi(p);
142                         if ((dim[ndim] < 0) || (lBound[ndim] < 0))
143                                 elog(ERROR, "array_in: array dimensions need to be positive");
144                         dim[ndim] = dim[ndim] - lBound[ndim] + 1;
145                         if (dim[ndim] < 0)
146                                 elog(ERROR, "array_in: upper_bound cannot be < lower_bound");
147                         p = q + 1;
148                         ndim++;
149                 }
150                 else
151                         done = true;
152         }
153
154         if (ndim == 0)
155         {
156                 if (*p == '{')
157                 {
158                         ndim = _ArrayCount(p, dim, typdelim);
159                         for (i = 0; i < ndim; lBound[i++] = 1);
160                 }
161                 else
162                         elog(ERROR, "array_in: Need to specify dimension");
163         }
164         else
165         {
166                 while (isspace(*p))
167                         p++;
168                 if (strncmp(p, ASSGN, strlen(ASSGN)))
169                         elog(ERROR, "array_in: missing assignment operator");
170                 p += strlen(ASSGN);
171                 while (isspace(*p))
172                         p++;
173         }
174
175 #ifdef ARRAYDEBUG
176         printf("array_in- ndim %d (", ndim);
177         for (i = 0; i < ndim; i++)
178         {
179                 printf(" %d", dim[i]);
180         };
181         printf(") for %s\n", string);
182 #endif
183
184         nitems = getNitems(ndim, dim);
185         if (nitems == 0)
186         {
187                 retval = (ArrayType *) palloc(sizeof(ArrayType));
188                 MemSet(retval, 0, sizeof(ArrayType));
189                 *(int32 *) retval = sizeof(ArrayType);
190                 return PointerGetDatum(retval);
191         }
192
193         if (*p == '{')
194         {
195                 /* array not a large object */
196                 dataPtr = (char *) _ReadArrayStr(p, nitems, ndim, dim, &inputproc, typelem,
197                                                         typmod, typdelim, typlen, typbyval, typalign,
198                                                                                  &nbytes);
199                 nbytes += ARR_OVERHEAD(ndim);
200                 retval = (ArrayType *) palloc(nbytes);
201                 MemSet(retval, 0, nbytes);
202                 memmove(retval, (char *) &nbytes, sizeof(int));
203                 memmove((char *) ARR_NDIM_PTR(retval), (char *) &ndim, sizeof(int));
204                 SET_LO_FLAG(false, retval);
205                 memmove((char *) ARR_DIMS(retval), (char *) dim, ndim * sizeof(int));
206                 memmove((char *) ARR_LBOUND(retval), (char *) lBound,
207                                 ndim * sizeof(int));
208
209                 /*
210                  * dataPtr is an array of arbitraystuff even though its type is
211                  * char* cast to char** to pass to _CopyArrayEls for now  - jolly
212                  */
213                 _CopyArrayEls((char **) dataPtr,
214                                           ARR_DATA_PTR(retval), nitems,
215                                           typlen, typalign, typbyval);
216         }
217         else
218         {
219 #ifdef LOARRAY
220                 int                     dummy,
221                                         bytes;
222                 bool            chunked = false;
223
224                 dataPtr = _ReadLOArray(p, &bytes, &dummy, &chunked, ndim,
225                                                            dim, typlen);
226                 nbytes = bytes + ARR_OVERHEAD(ndim);
227                 retval = (ArrayType *) palloc(nbytes);
228                 MemSet(retval, 0, nbytes);
229                 memmove(retval, (char *) &nbytes, sizeof(int));
230                 memmove((char *) ARR_NDIM_PTR(retval), (char *) &ndim, sizeof(int));
231                 SET_LO_FLAG(true, retval);
232                 SET_CHUNK_FLAG(chunked, retval);
233                 memmove((char *) ARR_DIMS(retval), (char *) dim, ndim * sizeof(int));
234                 memmove((char *) ARR_LBOUND(retval), (char *) lBound, ndim * sizeof(int));
235                 memmove(ARR_DATA_PTR(retval), dataPtr, bytes);
236 #endif
237                 elog(ERROR, "large object arrays not supported");
238                 PG_RETURN_NULL();
239         }
240         pfree(string_save);
241         return PointerGetDatum(retval);
242 }
243
244 /*-----------------------------------------------------------------------------
245  * _ArrayCount
246  *       Counts the number of dimensions and the *dim array for an array string.
247  *               The syntax for array input is C-like nested curly braces
248  *-----------------------------------------------------------------------------
249  */
250 static int
251 _ArrayCount(char *str, int *dim, int typdelim)
252 {
253         int                     nest_level = 0,
254                                 i;
255         int                     ndim = 0,
256                                 temp[MAXDIM];
257         bool            scanning_string = false;
258         bool            eoArray = false;
259         char       *q;
260
261         for (i = 0; i < MAXDIM; ++i)
262                 temp[i] = dim[i] = 0;
263
264         if (strncmp(str, "{}", 2) == 0)
265                 return 0;
266
267         q = str;
268         while (eoArray != true)
269         {
270                 bool            done = false;
271
272                 while (!done)
273                 {
274                         switch (*q)
275                         {
276                                 case '\\':
277                                         /* skip escaped characters (\ and ") inside strings */
278                                         if (scanning_string && *(q + 1))
279                                                 q++;
280                                         break;
281                                 case '\0':
282
283                                         /*
284                                          * Signal a premature end of the string.  DZ -
285                                          * 2-9-1996
286                                          */
287                                         elog(ERROR, "malformed array constant: %s", str);
288                                         break;
289                                 case '\"':
290                                         scanning_string = !scanning_string;
291                                         break;
292                                 case '{':
293                                         if (!scanning_string)
294                                         {
295                                                 temp[nest_level] = 0;
296                                                 nest_level++;
297                                         }
298                                         break;
299                                 case '}':
300                                         if (!scanning_string)
301                                         {
302                                                 if (!ndim)
303                                                         ndim = nest_level;
304                                                 nest_level--;
305                                                 if (nest_level)
306                                                         temp[nest_level - 1]++;
307                                                 if (nest_level == 0)
308                                                         eoArray = done = true;
309                                         }
310                                         break;
311                                 default:
312                                         if (!ndim)
313                                                 ndim = nest_level;
314                                         if (*q == typdelim && !scanning_string)
315                                                 done = true;
316                                         break;
317                         }
318                         if (!done)
319                                 q++;
320                 }
321                 temp[ndim - 1]++;
322                 q++;
323                 if (!eoArray)
324                         while (isspace(*q))
325                                 q++;
326         }
327         for (i = 0; i < ndim; ++i)
328                 dim[i] = temp[i];
329
330         return ndim;
331 }
332
333 /*---------------------------------------------------------------------------
334  * _ReadArrayStr :
335  *       parses the array string pointed by "arrayStr" and converts it in the
336  *       internal format. The external format expected is like C array
337  *       declaration. Unspecified elements are initialized to zero for fixed length
338  *       base types and to empty varlena structures for variable length base
339  *       types.
340  * result :
341  *       returns the internal representation of the array elements
342  *       nbytes is set to the size of the array in its internal representation.
343  *---------------------------------------------------------------------------
344  */
345 static char *
346 _ReadArrayStr(char *arrayStr,
347                           int nitems,
348                           int ndim,
349                           int *dim,
350                           FmgrInfo *inputproc,          /* function used for the
351                                                                                  * conversion */
352                           Oid typelem,
353                           int32 typmod,
354                           char typdelim,
355                           int typlen,
356                           bool typbyval,
357                           char typalign,
358                           int *nbytes)
359 {
360         int                     i,
361                                 nest_level = 0;
362         char       *p,
363                            *q,
364                            *r,
365                           **values;
366         bool            scanning_string = false;
367         int                     indx[MAXDIM],
368                                 prod[MAXDIM];
369         bool            eoArray = false;
370
371         mda_get_prod(ndim, dim, prod);
372         for (i = 0; i < ndim; indx[i++] = 0);
373         /* read array enclosed within {} */
374         values = (char **) palloc(nitems * sizeof(char *));
375         MemSet(values, 0, nitems * sizeof(char *));
376         q = p = arrayStr;
377
378         while (!eoArray)
379         {
380                 bool            done = false;
381                 int                     i = -1;
382
383                 while (!done)
384                 {
385                         switch (*q)
386                         {
387                                 case '\\':
388                                         /* Crunch the string on top of the backslash. */
389                                         for (r = q; *r != '\0'; r++)
390                                                 *r = *(r + 1);
391                                         break;
392                                 case '\"':
393                                         if (!scanning_string)
394                                         {
395                                                 while (p != q)
396                                                         p++;
397                                                 p++;    /* get p past first doublequote */
398                                         }
399                                         else
400                                                 *q = '\0';
401                                         scanning_string = !scanning_string;
402                                         break;
403                                 case '{':
404                                         if (!scanning_string)
405                                         {
406                                                 p++;
407                                                 nest_level++;
408                                                 if (nest_level > ndim)
409                                                         elog(ERROR, "array_in: illformed array constant");
410                                                 indx[nest_level - 1] = 0;
411                                                 indx[ndim - 1] = 0;
412                                         }
413                                         break;
414                                 case '}':
415                                         if (!scanning_string)
416                                         {
417                                                 if (i == -1)
418                                                         i = tuple2linear(ndim, indx, prod);
419                                                 nest_level--;
420                                                 if (nest_level == 0)
421                                                         eoArray = done = true;
422                                                 else
423                                                 {
424                                                         *q = '\0';
425                                                         indx[nest_level - 1]++;
426                                                 }
427                                         }
428                                         break;
429                                 default:
430                                         if (*q == typdelim && !scanning_string)
431                                         {
432                                                 if (i == -1)
433                                                         i = tuple2linear(ndim, indx, prod);
434                                                 done = true;
435                                                 indx[ndim - 1]++;
436                                         }
437                                         break;
438                         }
439                         if (!done)
440                                 q++;
441                 }
442                 *q = '\0';
443                 if (i >= nitems)
444                         elog(ERROR, "array_in: illformed array constant");
445                 values[i] = (char *) FunctionCall3(inputproc,
446                                                                                    CStringGetDatum(p),
447                                                                                    ObjectIdGetDatum(typelem),
448                                                                                    Int32GetDatum(typmod));
449                 p = ++q;
450                 if (!eoArray)
451
452                         /*
453                          * if not at the end of the array skip white space
454                          */
455                         while (isspace(*q))
456                         {
457                                 p++;
458                                 q++;
459                         }
460         }
461         if (typlen > 0)
462         {
463                 *nbytes = nitems * typlen;
464                 if (!typbyval)
465                         for (i = 0; i < nitems; i++)
466                                 if (!values[i])
467                                 {
468                                         values[i] = palloc(typlen);
469                                         MemSet(values[i], 0, typlen);
470                                 }
471         }
472         else
473         {
474                 for (i = 0, *nbytes = 0; i < nitems; i++)
475                 {
476                         if (values[i])
477                         {
478                                 if (typalign == 'd')
479                                         *nbytes += MAXALIGN(*(int32 *) values[i]);
480                                 else
481                                         *nbytes += INTALIGN(*(int32 *) values[i]);
482                         }
483                         else
484                         {
485                                 *nbytes += sizeof(int32);
486                                 values[i] = palloc(sizeof(int32));
487                                 *(int32 *) values[i] = sizeof(int32);
488                         }
489                 }
490         }
491         return (char *) values;
492 }
493
494
495 /*----------------------------------------------------------------------------
496  * Read data about an array to be stored as a large object
497  *----------------------------------------------------------------------------
498  */
499 #ifdef LOARRAY
500 static char *
501 _ReadLOArray(char *str,
502                          int *nbytes,
503                          int *fd,
504                          bool *chunkFlag,
505                          int ndim,
506                          int *dim,
507                          int baseSize)
508 {
509         char       *inputfile,
510                            *accessfile = NULL,
511                            *chunkfile = NULL;
512         char       *retStr,
513                            *_AdvanceBy1word();
514         Oid                     lobjId;
515
516         str = _AdvanceBy1word(str, &inputfile);
517
518         while (str != NULL)
519         {
520                 char       *word;
521
522                 str = _AdvanceBy1word(str, &word);
523
524                 if (!strcmp(word, "-chunk"))
525                 {
526                         if (str == NULL)
527                                 elog(ERROR, "array_in: access pattern file required");
528                         str = _AdvanceBy1word(str, &accessfile);
529                 }
530                 else if (!strcmp(word, "-noreorg"))
531                 {
532                         if (str == NULL)
533                                 elog(ERROR, "array_in: chunk file required");
534                         str = _AdvanceBy1word(str, &chunkfile);
535                 }
536                 else
537                         elog(ERROR, "usage: <input file> -chunk DEFAULT/<access pattern file> -invert/-native [-noreorg <chunk file>]");
538         }
539
540         if (inputfile == NULL)
541                 elog(ERROR, "array_in: missing file name");
542         lobjId = DatumGetObjectId(DirectFunctionCall1(lo_creat,
543                                                                                                   Int32GetDatum(0)));
544         *fd = DatumGetInt32(DirectFunctionCall2(lo_open,
545                                                                                         ObjectIdGetDatum(lobjId),
546                                                                                         Int32GetDatum(INV_READ)));
547         if (*fd < 0)
548                 elog(ERROR, "Large object create failed");
549         retStr = inputfile;
550         *nbytes = strlen(retStr) + 2;
551
552         if (accessfile)
553         {
554                 FILE       *afd;
555
556                 if ((afd = AllocateFile(accessfile, PG_BINARY_R)) == NULL)
557                         elog(ERROR, "unable to open access pattern file");
558                 *chunkFlag = true;
559                 retStr = _ChunkArray(*fd, afd, ndim, dim, baseSize, nbytes,
560                                                          chunkfile);
561                 FreeFile(afd);
562         }
563         return retStr;
564 }
565
566 #endif
567
568 static void
569 _CopyArrayEls(char **values,
570                           char *p,
571                           int nitems,
572                           int typlen,
573                           char typalign,
574                           bool typbyval)
575 {
576         int                     i;
577
578         for (i = 0; i < nitems; i++)
579         {
580                 int                     inc;
581
582                 inc = ArrayCastAndSet((Datum) values[i], typbyval, typlen, p);
583                 p += inc;
584                 if (!typbyval)
585                         pfree(values[i]);
586         }
587         pfree(values);
588 }
589
590 /*-------------------------------------------------------------------------
591  * array_out :
592  *                 takes the internal representation of an array and returns a string
593  *                containing the array in its external format.
594  *-------------------------------------------------------------------------
595  */
596 Datum
597 array_out(PG_FUNCTION_ARGS)
598 {
599         ArrayType  *v = (ArrayType *) PG_GETARG_VARLENA_P(0);
600         Oid                     element_type = PG_GETARG_OID(1);
601         int                     typlen;
602         bool            typbyval;
603         char            typdelim;
604         Oid                     typoutput,
605                                 typelem;
606         FmgrInfo        outputproc;
607         char            typalign;
608         char       *p,
609                            *tmp,
610                            *retval,
611                           **values,
612                                 delim[2];
613         int                     nitems,
614                                 overall_length,
615                                 i,
616                                 j,
617                                 k,
618 #ifndef TCL_ARRAYS
619                                 l,
620 #endif
621                                 indx[MAXDIM];
622         int                     ndim,
623                            *dim;
624
625         if (v == (ArrayType *) NULL)
626                 PG_RETURN_CSTRING((char *) NULL);
627
628         if (ARR_IS_LO(v) == true)
629         {
630                 text       *p;
631                 int                     plen,
632                                         nbytes;
633
634                 p = (text *) DatumGetPointer(DirectFunctionCall1(array_dims,
635                                                                                                                  PointerGetDatum(v)));
636                 plen = VARSIZE(p) - VARHDRSZ;
637
638                 /* get a wide string to print to */
639                 nbytes = strlen(ARR_DATA_PTR(v)) + strlen(ASSGN) + plen + 1;
640                 retval = (char *) palloc(nbytes);
641
642                 memcpy(retval, VARDATA(p), plen);
643                 strcpy(retval + plen, ASSGN);
644                 strcat(retval, ARR_DATA_PTR(v));
645                 pfree(p);
646                 PG_RETURN_CSTRING(retval);
647         }
648
649         system_cache_lookup(element_type, false, &typlen, &typbyval,
650                                                 &typdelim, &typelem, &typoutput, &typalign);
651         fmgr_info(typoutput, &outputproc);
652         sprintf(delim, "%c", typdelim);
653         ndim = ARR_NDIM(v);
654         dim = ARR_DIMS(v);
655         nitems = getNitems(ndim, dim);
656
657         if (nitems == 0)
658         {
659                 retval = (char *) palloc(3);
660                 retval[0] = '{';
661                 retval[1] = '}';
662                 retval[2] = '\0';
663                 PG_RETURN_CSTRING(retval);
664         }
665
666         p = ARR_DATA_PTR(v);
667         overall_length = 1;                     /* [TRH] don't forget to count \0 at end. */
668         values = (char **) palloc(nitems * sizeof(char *));
669         for (i = 0; i < nitems; i++)
670         {
671                 if (typbyval)
672                 {
673                         switch (typlen)
674                         {
675                                 case 1:
676                                         values[i] = DatumGetCString(FunctionCall3(&outputproc,
677                                                                                                 CharGetDatum(*p),
678                                                                                                 ObjectIdGetDatum(typelem),
679                                                                                                 Int32GetDatum(-1)));
680                                         break;
681                                 case 2:
682                                         values[i] = DatumGetCString(FunctionCall3(&outputproc,
683                                                                                                 Int16GetDatum(*(int16 *) p),
684                                                                                                 ObjectIdGetDatum(typelem),
685                                                                                                 Int32GetDatum(-1)));
686                                         break;
687                                 case 3:
688                                 case 4:
689                                         values[i] = DatumGetCString(FunctionCall3(&outputproc,
690                                                                                                 Int32GetDatum(*(int32 *) p),
691                                                                                                 ObjectIdGetDatum(typelem),
692                                                                                                 Int32GetDatum(-1)));
693                                         break;
694                         }
695                         p += typlen;
696                 }
697                 else
698                 {
699                         values[i] = DatumGetCString(FunctionCall3(&outputproc,
700                                                                                                 PointerGetDatum(p),
701                                                                                                 ObjectIdGetDatum(typelem),
702                                                                                                 Int32GetDatum(-1)));
703                         if (typlen > 0)
704                                 p += typlen;
705                         else
706                                 p += INTALIGN(*(int32 *) p);
707
708                         /*
709                          * For the pair of double quotes
710                          */
711                         overall_length += 2;
712                 }
713                 for (tmp = values[i]; *tmp; tmp++)
714                 {
715                         overall_length += 1;
716 #ifndef TCL_ARRAYS
717                         if (*tmp == '"')
718                                 overall_length += 1;
719 #endif
720                 }
721                 overall_length += 1;
722         }
723
724         /*
725          * count total number of curly braces in output string
726          */
727         for (i = j = 0, k = 1; i < ndim; k *= dim[i++], j += k);
728
729         p = (char *) palloc(overall_length + 2 * j);
730         retval = p;
731
732         strcpy(p, "{");
733         for (i = 0; i < ndim; indx[i++] = 0);
734         j = 0;
735         k = 0;
736         do
737         {
738                 for (i = j; i < ndim - 1; i++)
739                         strcat(p, "{");
740
741                 /*
742                  * Surround anything that is not passed by value in double quotes.
743                  * See above for more details.
744                  */
745                 if (!typbyval)
746                 {
747                         strcat(p, "\"");
748 #ifndef TCL_ARRAYS
749                         l = strlen(p);
750                         for (tmp = values[k]; *tmp; tmp++)
751                         {
752                                 if (*tmp == '"')
753                                         p[l++] = '\\';
754                                 p[l++] = *tmp;
755                         }
756                         p[l] = '\0';
757 #else
758                         strcat(p, values[k]);
759 #endif
760                         strcat(p, "\"");
761                 }
762                 else
763                         strcat(p, values[k]);
764                 pfree(values[k++]);
765
766                 for (i = ndim - 1; i >= 0; i--)
767                 {
768                         indx[i] = (indx[i] + 1) % dim[i];
769                         if (indx[i])
770                         {
771                                 strcat(p, delim);
772                                 break;
773                         }
774                         else
775                                 strcat(p, "}");
776                 }
777                 j = i;
778         } while (j != -1);
779
780         pfree(values);
781         PG_RETURN_CSTRING(retval);
782 }
783
784 /*-----------------------------------------------------------------------------
785  * array_dims :
786  *                returns the dimensions of the array pointed to by "v", as a "text"
787  *----------------------------------------------------------------------------
788  */
789 Datum
790 array_dims(PG_FUNCTION_ARGS)
791 {
792         ArrayType  *v = (ArrayType *) PG_GETARG_VARLENA_P(0);
793         text       *result;
794         char       *p;
795         int                     nbytes,
796                                 i;
797         int                *dimv,
798                            *lb;
799
800         nbytes = ARR_NDIM(v) * 33 + 1;
801         /*
802          * 33 since we assume 15 digits per number + ':' +'[]'
803          *
804          * +1 allows for temp trailing null
805          */
806
807         result = (text *) palloc(nbytes + VARHDRSZ);
808         MemSet(result, 0, nbytes + VARHDRSZ);
809         p = VARDATA(result);
810
811         dimv = ARR_DIMS(v);
812         lb = ARR_LBOUND(v);
813
814         for (i = 0; i < ARR_NDIM(v); i++)
815         {
816                 sprintf(p, "[%d:%d]", lb[i], dimv[i] + lb[i] - 1);
817                 p += strlen(p);
818         }
819         VARSIZE(result) = strlen(VARDATA(result)) + VARHDRSZ;
820
821         PG_RETURN_TEXT_P(result);
822 }
823
824 /*---------------------------------------------------------------------------
825  * array_ref :
826  *        This routine takes an array pointer and an index array and returns
827  *        a pointer to the referred element if element is passed by
828  *        reference otherwise returns the value of the referred element.
829  *---------------------------------------------------------------------------
830  */
831 Datum
832 array_ref(ArrayType *array,
833                   int nSubscripts,
834                   int *indx,
835                   bool elmbyval,
836                   int elmlen,
837                   int arraylen,
838                   bool *isNull)
839 {
840         int                     i,
841                                 ndim,
842                            *dim,
843                            *lb,
844                                 offset,
845                                 nbytes;
846         struct varlena *v = NULL;
847         Datum           result;
848         char       *retval;
849
850         if (array == (ArrayType *) NULL)
851                 RETURN_NULL(Datum);
852         if (arraylen > 0)
853         {
854
855                 /*
856                  * fixed length arrays -- these are assumed to be 1-d
857                  */
858                 if (indx[0] * elmlen > arraylen)
859                         elog(ERROR, "array_ref: array bound exceeded");
860                 retval = (char *) array + indx[0] * elmlen;
861                 return _ArrayCast(retval, elmbyval, elmlen);
862         }
863         dim = ARR_DIMS(array);
864         lb = ARR_LBOUND(array);
865         ndim = ARR_NDIM(array);
866         nbytes = (*(int32 *) array) - ARR_OVERHEAD(ndim);
867
868         if (!SanityCheckInput(ndim, nSubscripts, dim, lb, indx))
869                 RETURN_NULL(Datum);
870
871         offset = GetOffset(nSubscripts, dim, lb, indx);
872
873         if (ARR_IS_LO(array))
874         {
875                 char       *lo_name;
876                 int                     fd = 0;
877
878                 /* We are assuming fixed element lengths here */
879                 offset *= elmlen;
880                 lo_name = (char *) ARR_DATA_PTR(array);
881 #ifdef LOARRAY
882                 if ((fd = LOopen(lo_name, ARR_IS_INV(array) ? INV_READ : O_RDONLY)) < 0)
883                         RETURN_NULL(Datum);
884 #endif
885                 if (ARR_IS_CHUNKED(array))
886                         v = _ReadChunkArray1El(indx, elmlen, fd, array, isNull);
887                 else
888                 {
889                         if (DatumGetInt32(DirectFunctionCall3(lo_lseek,
890                                                           Int32GetDatum(fd),
891                                                           Int32GetDatum(offset),
892                                                           Int32GetDatum(SEEK_SET))) < 0)
893                                 RETURN_NULL(Datum);
894 #ifdef LOARRAY
895                         v = (struct varlena *)
896                                 DatumGetPointer(DirectFunctionCall2(loread,
897                                                                                                         Int32GetDatum(fd),
898                                                                                                         Int32GetDatum(elmlen)));
899 #endif
900                 }
901                 if (*isNull)
902                         RETURN_NULL(Datum);
903                 if (VARSIZE(v) - VARHDRSZ < elmlen)
904                         RETURN_NULL(Datum);
905                 DirectFunctionCall1(lo_close, Int32GetDatum(fd));
906                 result = _ArrayCast((char *) VARDATA(v), elmbyval, elmlen);
907                 if (! elmbyval)
908                 {                                               /* not by value */
909                         char       *tempdata = palloc(elmlen);
910
911                         memmove(tempdata, DatumGetPointer(result), elmlen);
912                         result = PointerGetDatum(tempdata);
913                 }
914                 pfree(v);
915                 return result;
916         }
917
918         if (elmlen > 0)
919         {
920                 offset = offset * elmlen;
921                 /* off the end of the array */
922                 if (nbytes - offset < 1)
923                         RETURN_NULL(Datum);
924                 retval = ARR_DATA_PTR(array) + offset;
925                 return _ArrayCast(retval, elmbyval, elmlen);
926         }
927         else
928         {
929                 int                     bytes = nbytes;
930
931                 retval = ARR_DATA_PTR(array);
932                 i = 0;
933                 while (bytes > 0)
934                 {
935                         if (i == offset)
936                                 return PointerGetDatum(retval);
937                         bytes -= INTALIGN(*(int32 *) retval);
938                         retval += INTALIGN(*(int32 *) retval);
939                         i++;
940                 }
941                 RETURN_NULL(Datum);
942         }
943 }
944
945 /*-----------------------------------------------------------------------------
946  * array_clip :
947  *                This routine takes an array and a range of indices (upperIndex and
948  *                 lowerIndx), creates a new array structure for the referred elements
949  *                 and returns a pointer to it.
950  *-----------------------------------------------------------------------------
951  */
952 ArrayType *
953 array_clip(ArrayType *array,
954                    int nSubscripts,
955                    int *upperIndx,
956                    int *lowerIndx,
957                    bool elmbyval,
958                    int elmlen,
959                    bool *isNull)
960 {
961         int                     i,
962                                 ndim,
963                            *dim,
964                            *lb,
965                                 nbytes;
966         ArrayType  *newArr;
967         int                     bytes,
968                                 span[MAXDIM];
969
970         /* timer_start(); */
971         if (array == (ArrayType *) NULL)
972                 RETURN_NULL(ArrayType *);
973         dim = ARR_DIMS(array);
974         lb = ARR_LBOUND(array);
975         ndim = ARR_NDIM(array);
976         nbytes = (*(int32 *) array) - ARR_OVERHEAD(ndim);
977
978         if (!SanityCheckInput(ndim, nSubscripts, dim, lb, upperIndx) ||
979                 !SanityCheckInput(ndim, nSubscripts, dim, lb, lowerIndx))
980                 RETURN_NULL(ArrayType *);
981
982         for (i = 0; i < nSubscripts; i++)
983                 if (lowerIndx[i] > upperIndx[i])
984                         elog(ERROR, "lowerIndex cannot be larger than upperIndx");
985         mda_get_range(nSubscripts, span, lowerIndx, upperIndx);
986
987         if (ARR_IS_LO(array))
988         {
989 #ifdef LOARRAY
990                 char       *lo_name;
991
992 #endif
993                 char       *newname = NULL;
994                 int                     fd = 0,
995                                         newfd = 0,
996                                         isDestLO = true,
997                                         rsize;
998
999                 if (elmlen < 0)
1000                         elog(ERROR, "array_clip: array of variable length objects not implemented");
1001 #ifdef LOARRAY
1002                 lo_name = (char *) ARR_DATA_PTR(array);
1003                 if ((fd = LOopen(lo_name, ARR_IS_INV(array) ? INV_READ : O_RDONLY)) < 0)
1004                         RETURN_NULL(ArrayType *);
1005                 newname = _array_newLO(&newfd, Unix);
1006 #endif
1007                 bytes = strlen(newname) + 1 + ARR_OVERHEAD(nSubscripts);
1008                 newArr = (ArrayType *) palloc(bytes);
1009                 memmove(newArr, array, sizeof(ArrayType));
1010                 memmove(newArr, &bytes, sizeof(int));
1011                 memmove(ARR_DIMS(newArr), span, nSubscripts * sizeof(int));
1012                 memmove(ARR_LBOUND(newArr), lowerIndx, nSubscripts * sizeof(int));
1013                 strcpy(ARR_DATA_PTR(newArr), newname);
1014
1015                 rsize = compute_size(lowerIndx, upperIndx, nSubscripts, elmlen);
1016                 if (rsize < MAX_BUFF_SIZE)
1017                 {
1018                         char       *buff;
1019
1020                         rsize += VARHDRSZ;
1021                         buff = palloc(rsize);
1022                         if (buff)
1023                                 isDestLO = false;
1024                         if (ARR_IS_CHUNKED(array))
1025                         {
1026                                 _ReadChunkArray(lowerIndx, upperIndx, elmlen, fd, &(buff[VARHDRSZ]),
1027                                                                 array, 0, isNull);
1028                         }
1029                         else
1030                         {
1031                                 _ReadArray(lowerIndx, upperIndx, elmlen, fd, (int) &(buff[VARHDRSZ]),
1032                                                    array,
1033                                                    0, isNull);
1034                         }
1035                         memmove(buff, &rsize, VARHDRSZ);
1036 #ifdef LOARRAY
1037                         if (!*isNull)
1038                                 bytes = DatumGetInt32(DirectFunctionCall2(lowrite,
1039                                                                           Int32GetDatum(newfd),
1040                                                                           PointerGetDatum(buff)));
1041 #endif
1042                         pfree(buff);
1043                 }
1044                 if (isDestLO)
1045                 {
1046                         if (ARR_IS_CHUNKED(array))
1047                         {
1048                                 _ReadChunkArray(lowerIndx, upperIndx, elmlen, fd, (char *) newfd, array,
1049                                                                 1, isNull);
1050                         }
1051                         else
1052                                 _ReadArray(lowerIndx, upperIndx, elmlen, fd, newfd, array, 1, isNull);
1053                 }
1054 #ifdef LOARRAY
1055                 LOclose(fd);
1056                 LOclose(newfd);
1057 #endif
1058                 if (*isNull)
1059                 {
1060                         pfree(newArr);
1061                         newArr = NULL;
1062                 }
1063                 /* timer_end(); */
1064                 return newArr;
1065         }
1066
1067         if (elmlen > 0)
1068         {
1069                 bytes = getNitems(nSubscripts, span);
1070                 bytes = bytes * elmlen + ARR_OVERHEAD(nSubscripts);
1071         }
1072         else
1073         {
1074                 bytes = _ArrayClipCount(lowerIndx, upperIndx, array);
1075                 bytes += ARR_OVERHEAD(nSubscripts);
1076         }
1077         newArr = (ArrayType *) palloc(bytes);
1078         memmove(newArr, array, sizeof(ArrayType));
1079         memmove(newArr, &bytes, sizeof(int));
1080         memmove(ARR_DIMS(newArr), span, nSubscripts * sizeof(int));
1081         memmove(ARR_LBOUND(newArr), lowerIndx, nSubscripts * sizeof(int));
1082         _ArrayRange(lowerIndx, upperIndx, elmlen, ARR_DATA_PTR(newArr), array, 1);
1083         return newArr;
1084 }
1085
1086 /*-----------------------------------------------------------------------------
1087  * array_set  :
1088  *                This routine sets the value of an array location (specified by
1089  *                an index array) to a new value specified by "dataValue".
1090  * result :
1091  *                returns a pointer to the modified array.
1092  *-----------------------------------------------------------------------------
1093  */
1094 ArrayType *
1095 array_set(ArrayType *array,
1096                   int nSubscripts,
1097                   int *indx,
1098                   Datum dataValue,
1099                   bool elmbyval,
1100                   int elmlen,
1101                   int arraylen,
1102                   bool *isNull)
1103 {
1104         int                     ndim,
1105                            *dim,
1106                            *lb,
1107                                 offset,
1108                                 nbytes;
1109         char       *pos;
1110
1111         if (array == (ArrayType *) NULL)
1112                 RETURN_NULL(ArrayType *);
1113         if (arraylen > 0)
1114         {
1115
1116                 /*
1117                  * fixed length arrays -- these are assumed to be 1-d
1118                  */
1119                 if (indx[0] * elmlen > arraylen)
1120                         elog(ERROR, "array_ref: array bound exceeded");
1121                 pos = (char *) array + indx[0] * elmlen;
1122                 ArrayCastAndSet(dataValue, elmbyval, elmlen, pos);
1123                 return array;
1124         }
1125         dim = ARR_DIMS(array);
1126         lb = ARR_LBOUND(array);
1127         ndim = ARR_NDIM(array);
1128         nbytes = (*(int32 *) array) - ARR_OVERHEAD(ndim);
1129
1130         if (!SanityCheckInput(ndim, nSubscripts, dim, lb, indx))
1131         {
1132                 elog(ERROR, "array_set: array bound exceeded");
1133                 return array;
1134         }
1135         offset = GetOffset(nSubscripts, dim, lb, indx);
1136
1137         if (ARR_IS_LO(array))
1138         {
1139                 int                     fd = 0;
1140                 struct varlena *v;
1141
1142                 /* We are assuming fixed element lengths here */
1143                 offset *= elmlen;
1144 #ifdef LOARRAY
1145                 char       *lo_name;
1146
1147                 lo_name = ARR_DATA_PTR(array);
1148                 if ((fd = LOopen(lo_name, ARR_IS_INV(array) ? INV_WRITE : O_WRONLY)) < 0)
1149                         return array;
1150 #endif
1151                 if (DatumGetInt32(DirectFunctionCall3(lo_lseek,
1152                                                           Int32GetDatum(fd),
1153                                                           Int32GetDatum(offset),
1154                                                           Int32GetDatum(SEEK_SET))) < 0)
1155                         return array;
1156                 v = (struct varlena *) palloc(elmlen + VARHDRSZ);
1157                 VARSIZE(v) = elmlen + VARHDRSZ;
1158                 ArrayCastAndSet(dataValue, elmbyval, elmlen, VARDATA(v));
1159 #ifdef LOARRAY
1160                 if (DatumGetInt32(DirectFunctionCall2(lowrite,
1161                                                                                           Int32GetDatum(fd),
1162                                                                                           PointerGetDatum(v)))
1163                         != elmlen)
1164                         RETURN_NULL(ArrayType *);
1165 #endif
1166                 pfree(v);
1167                 DirectFunctionCall1(lo_close, Int32GetDatum(fd));
1168                 return array;
1169         }
1170         if (elmlen > 0)
1171         {
1172                 offset = offset * elmlen;
1173                 /* off the end of the array */
1174                 if (nbytes - offset < 1)
1175                         return array;
1176                 pos = ARR_DATA_PTR(array) + offset;
1177         }
1178         else
1179         {
1180                 ArrayType  *newarray;
1181                 char       *elt_ptr;
1182                 int                     oldsize,
1183                                         newsize,
1184                                         oldlen,
1185                                         newlen,
1186                                         lth0,
1187                                         lth1,
1188                                         lth2;
1189
1190                 elt_ptr = array_seek(ARR_DATA_PTR(array), -1, offset);
1191                 oldlen = INTALIGN(*(int32 *) elt_ptr);
1192                 newlen = INTALIGN(*(int32 *) DatumGetPointer(dataValue));
1193
1194                 if (oldlen == newlen)
1195                 {
1196                         /* new element with same size, overwrite old data */
1197                         ArrayCastAndSet(dataValue, elmbyval, elmlen, elt_ptr);
1198                         return array;
1199                 }
1200
1201                 /* new element with different size, reallocate the array */
1202                 oldsize = array->size;
1203                 lth0 = ARR_OVERHEAD(nSubscripts);
1204                 lth1 = (int) (elt_ptr - ARR_DATA_PTR(array));
1205                 lth2 = (int) (oldsize - lth0 - lth1 - oldlen);
1206                 newsize = lth0 + lth1 + newlen + lth2;
1207
1208                 newarray = (ArrayType *) palloc(newsize);
1209                 memmove((char *) newarray, (char *) array, lth0 + lth1);
1210                 newarray->size = newsize;
1211                 newlen = ArrayCastAndSet(dataValue, elmbyval, elmlen,
1212                                                                  (char *) newarray + lth0 + lth1);
1213                 memmove((char *) newarray + lth0 + lth1 + newlen,
1214                                 (char *) array + lth0 + lth1 + oldlen, lth2);
1215
1216                 /* ??? who should free this storage ??? */
1217                 return newarray;
1218         }
1219         ArrayCastAndSet(dataValue, elmbyval, elmlen, pos);
1220         return array;
1221 }
1222
1223 /*----------------------------------------------------------------------------
1224  * array_assgn :
1225  *                This routine sets the value of a range of array locations (specified
1226  *                by upper and lower index values ) to new values passed as
1227  *                another array
1228  * result :
1229  *                returns a pointer to the modified array.
1230  *----------------------------------------------------------------------------
1231  */
1232 ArrayType *
1233 array_assgn(ArrayType *array,
1234                         int nSubscripts,
1235                         int *upperIndx,
1236                         int *lowerIndx,
1237                         ArrayType *newArr,
1238                         bool elmbyval,
1239                         int elmlen,
1240                         bool *isNull)
1241 {
1242         int                     i,
1243                                 ndim,
1244                            *dim,
1245                            *lb;
1246
1247         if (array == (ArrayType *) NULL)
1248                 RETURN_NULL(ArrayType *);
1249         if (elmlen < 0)
1250                 elog(ERROR, "array_assgn: updates on arrays of variable length elements not implemented");
1251
1252         dim = ARR_DIMS(array);
1253         lb = ARR_LBOUND(array);
1254         ndim = ARR_NDIM(array);
1255
1256         if (!SanityCheckInput(ndim, nSubscripts, dim, lb, upperIndx) ||
1257                 !SanityCheckInput(ndim, nSubscripts, dim, lb, lowerIndx))
1258                 RETURN_NULL(ArrayType *);
1259
1260         for (i = 0; i < nSubscripts; i++)
1261                 if (lowerIndx[i] > upperIndx[i])
1262                         elog(ERROR, "lowerIndex larger than upperIndx");
1263
1264         if (ARR_IS_LO(array))
1265         {
1266                 int                     fd = 0,
1267                                         newfd = 0;
1268
1269 #ifdef LOARRAY
1270                 char       *lo_name;
1271
1272                 lo_name = (char *) ARR_DATA_PTR(array);
1273                 if ((fd = LOopen(lo_name, ARR_IS_INV(array) ? INV_WRITE : O_WRONLY)) < 0)
1274                         return array;
1275 #endif
1276                 if (ARR_IS_LO(newArr))
1277                 {
1278 #ifdef LOARRAY
1279                         lo_name = (char *) ARR_DATA_PTR(newArr);
1280                         if ((newfd = LOopen(lo_name, ARR_IS_INV(newArr) ? INV_READ : O_RDONLY)) < 0)
1281                                 return array;
1282 #endif
1283                         _LOArrayRange(lowerIndx, upperIndx, elmlen, fd, newfd, array, 1, isNull);
1284                         DirectFunctionCall1(lo_close, Int32GetDatum(newfd));
1285                 }
1286                 else
1287                 {
1288                         _LOArrayRange(lowerIndx, upperIndx, elmlen, fd, (int) ARR_DATA_PTR(newArr),
1289                                                   array, 0, isNull);
1290                 }
1291                 DirectFunctionCall1(lo_close, Int32GetDatum(fd));
1292                 return array;
1293         }
1294         _ArrayRange(lowerIndx, upperIndx, elmlen, ARR_DATA_PTR(newArr), array, 0);
1295         return array;
1296 }
1297
1298 /*
1299  * array_map()
1300  *
1301  * Map an array through an arbitrary function.  Return a new array with
1302  * same dimensions and each source element transformed by fn().  Each
1303  * source element is passed as the first argument to fn(); additional
1304  * arguments to be passed to fn() can be specified by the caller.
1305  * The output array can have a different element type than the input.
1306  *
1307  * Parameters are:
1308  * * fcinfo: a function-call data structure pre-constructed by the caller
1309  *   to be ready to call the desired function, with everything except the
1310  *   first argument position filled in.  In particular, flinfo identifies
1311  *   the function fn(), and if nargs > 1 then argument positions after the
1312  *   first must be preset to the additional values to be passed.  The
1313  *   first argument position initially holds the input array value.
1314  * * inpType: OID of element type of input array.  This must be the same as,
1315  *   or binary-compatible with, the first argument type of fn().
1316  * * retType: OID of element type of output array.  This must be the same as,
1317  *   or binary-compatible with, the result type of fn().
1318  *
1319  * NB: caller must assure that input array is not NULL.  Currently,
1320  * any additional parameters passed to fn() may not be specified as NULL
1321  * either.
1322  */
1323 Datum
1324 array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType)
1325 {
1326         ArrayType  *v;
1327         ArrayType  *result;
1328         char      **values;
1329         char       *elt;
1330         int                *dim;
1331         int                     ndim;
1332         int                     nitems;
1333         int                     i;
1334         int                     nbytes = 0;
1335         int                     inp_typlen;
1336         bool            inp_typbyval;
1337         int                     typlen;
1338         bool            typbyval;
1339         char            typdelim;
1340         Oid                     typelem;
1341         Oid                     proc;
1342         char            typalign;
1343         char       *s;
1344         char       *p;
1345
1346         /* Get input array */
1347         if (fcinfo->nargs < 1)
1348                 elog(ERROR, "array_map: invalid nargs: %d", fcinfo->nargs);
1349         if (PG_ARGISNULL(0))
1350                 elog(ERROR, "array_map: null input array");
1351         v = (ArrayType *) PG_GETARG_VARLENA_P(0);
1352
1353         /* Large objects not yet supported */
1354         if (ARR_IS_LO(v) == true)
1355                 elog(ERROR, "array_map: large objects not supported");
1356
1357         ndim = ARR_NDIM(v);
1358         dim = ARR_DIMS(v);
1359         nitems = getNitems(ndim, dim);
1360
1361         /* Check for empty array */
1362         if (nitems <= 0)
1363                 PG_RETURN_POINTER(v);
1364
1365         /* Lookup source and result types. Unneeded variables are reused. */
1366         system_cache_lookup(inpType, false, &inp_typlen, &inp_typbyval,
1367                                                 &typdelim, &typelem, &proc, &typalign);
1368         system_cache_lookup(retType, false, &typlen, &typbyval,
1369                                                 &typdelim, &typelem, &proc, &typalign);
1370
1371         /* Allocate temporary array for new values */
1372         values = (char **) palloc(nitems * sizeof(char *));
1373         MemSet(values, 0, nitems * sizeof(char *));
1374
1375         /* Loop over source data */
1376         s = (char *) ARR_DATA_PTR(v);
1377         for (i = 0; i < nitems; i++)
1378         {
1379                 /* Get source element */
1380                 if (inp_typbyval)
1381                 {
1382                         switch (inp_typlen)
1383                         {
1384                                 case 1:
1385                                         elt = (char *) ((int) (*(char *) s));
1386                                         break;
1387                                 case 2:
1388                                         elt = (char *) ((int) (*(int16 *) s));
1389                                         break;
1390                                 case 3:
1391                                 case 4:
1392                                 default:
1393                                         elt = (char *) (*(int32 *) s);
1394                                         break;
1395                         }
1396                         s += inp_typlen;
1397                 }
1398                 else
1399                 {
1400                         elt = s;
1401                         if (inp_typlen > 0)
1402                                 s += inp_typlen;
1403                         else
1404                                 s += INTALIGN(*(int32 *) s);
1405                 }
1406
1407                 /*
1408                  * Apply the given function to source elt and extra args.
1409                  *
1410                  * We assume the extra args are non-NULL, so need not check
1411                  * whether fn() is strict.  Would need to do more work here
1412                  * to support arrays containing nulls, too.
1413                  */
1414                 fcinfo->arg[0] = (Datum) elt;
1415                 fcinfo->argnull[0] = false;
1416                 fcinfo->isnull = false;
1417                 p = (char *) FunctionCallInvoke(fcinfo);
1418                 if (fcinfo->isnull)
1419                         elog(ERROR, "array_map: cannot handle NULL in array");
1420
1421                 /* Update values and total result size */
1422                 if (typbyval)
1423                 {
1424                         values[i] = p;
1425                         nbytes += typlen;
1426                 }
1427                 else
1428                 {
1429                         int                     len;
1430
1431                         len = ((typlen > 0) ? typlen : INTALIGN(*(int32 *) p));
1432                         /* Needed because _CopyArrayEls tries to pfree items */
1433                         if (p == elt)
1434                         {
1435                                 p = (char *) palloc(len);
1436                                 memcpy(p, elt, len);
1437                         }
1438                         values[i] = p;
1439                         nbytes += len;
1440                 }
1441         }
1442
1443         /* Allocate and initialize the result array */
1444         nbytes += ARR_OVERHEAD(ndim);
1445         result = (ArrayType *) palloc(nbytes);
1446         MemSet(result, 0, nbytes);
1447
1448         memcpy((char *) result, (char *) &nbytes, sizeof(int));
1449         memcpy((char *) ARR_NDIM_PTR(result), (char *) &ndim, sizeof(int));
1450         memcpy((char *) ARR_DIMS(result), ARR_DIMS(v), 2 * ndim * sizeof(int));
1451
1452         /* Copy new values into the result array. values is pfreed. */
1453         _CopyArrayEls((char **) values,
1454                                   ARR_DATA_PTR(result), nitems,
1455                                   typlen, typalign, typbyval);
1456
1457         PG_RETURN_POINTER(result);
1458 }
1459
1460 /*-----------------------------------------------------------------------------
1461  * array_eq :
1462  *                compares two arrays for equality
1463  * result :
1464  *                returns true if the arrays are equal, false otherwise.
1465  *-----------------------------------------------------------------------------
1466  */
1467 Datum
1468 array_eq(PG_FUNCTION_ARGS)
1469 {
1470         ArrayType  *array1 = (ArrayType *) PG_GETARG_VARLENA_P(0);
1471         ArrayType  *array2 = (ArrayType *) PG_GETARG_VARLENA_P(1);
1472
1473         if (*(int32 *) array1 != *(int32 *) array2)
1474                 PG_RETURN_BOOL(false);
1475         if (memcmp(array1, array2, *(int32 *) array1) != 0)
1476                 PG_RETURN_BOOL(false);
1477         PG_RETURN_BOOL(true);
1478 }
1479
1480 /***************************************************************************/
1481 /******************|              Support  Routines                       |*****************/
1482 /***************************************************************************/
1483 static void
1484 system_cache_lookup(Oid element_type,
1485                                         bool input,
1486                                         int *typlen,
1487                                         bool *typbyval,
1488                                         char *typdelim,
1489                                         Oid *typelem,
1490                                         Oid *proc,
1491                                         char *typalign)
1492 {
1493         HeapTuple       typeTuple;
1494         Form_pg_type typeStruct;
1495
1496         typeTuple = SearchSysCacheTuple(TYPEOID,
1497                                                                         ObjectIdGetDatum(element_type),
1498                                                                         0, 0, 0);
1499
1500         if (!HeapTupleIsValid(typeTuple))
1501         {
1502                 elog(ERROR, "array_out: Cache lookup failed for type %u\n",
1503                          element_type);
1504                 return;
1505         }
1506         typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
1507         *typlen = typeStruct->typlen;
1508         *typbyval = typeStruct->typbyval;
1509         *typdelim = typeStruct->typdelim;
1510         *typelem = typeStruct->typelem;
1511         *typalign = typeStruct->typalign;
1512         if (input)
1513                 *proc = typeStruct->typinput;
1514         else
1515                 *proc = typeStruct->typoutput;
1516 }
1517
1518 static Datum
1519 _ArrayCast(char *value, bool byval, int len)
1520 {
1521         if (byval)
1522         {
1523                 switch (len)
1524                 {
1525                                 case 1:
1526                                 return (Datum) *value;
1527                         case 2:
1528                                 return (Datum) *(int16 *) value;
1529                         case 3:
1530                         case 4:
1531                                 return (Datum) *(int32 *) value;
1532                         default:
1533                                 elog(ERROR, "array_ref: byval and elt len > 4!");
1534                                 break;
1535                 }
1536         }
1537         else
1538                 return (Datum) value;
1539         return 0;
1540 }
1541
1542
1543 static int
1544 ArrayCastAndSet(Datum src,
1545                                 bool typbyval,
1546                                 int typlen,
1547                                 char *dest)
1548 {
1549         int                     inc;
1550
1551         if (typlen > 0)
1552         {
1553                 if (typbyval)
1554                 {
1555                         switch (typlen)
1556                         {
1557                                 case 1:
1558                                         *dest = DatumGetChar(src);
1559                                         break;
1560                                 case 2:
1561                                         *(int16 *) dest = DatumGetInt16(src);
1562                                         break;
1563                                 case 4:
1564                                         *(int32 *) dest = DatumGetInt32(src);
1565                                         break;
1566                         }
1567                 }
1568                 else
1569                         memmove(dest, DatumGetPointer(src), typlen);
1570                 inc = typlen;
1571         }
1572         else
1573         {
1574                 memmove(dest, DatumGetPointer(src), *(int32 *) DatumGetPointer(src));
1575                 inc = (INTALIGN(*(int32 *) DatumGetPointer(src)));
1576         }
1577         return inc;
1578 }
1579
1580 #ifdef LOARRAY
1581 static char *
1582 _AdvanceBy1word(char *str, char **word)
1583 {
1584         char       *retstr,
1585                            *space;
1586
1587         *word = NULL;
1588         if (str == NULL)
1589                 return str;
1590         while (isspace(*str))
1591                 str++;
1592         *word = str;
1593         if ((space = (char *) strchr(str, ' ')) != (char *) NULL)
1594         {
1595                 retstr = space + 1;
1596                 *space = '\0';
1597         }
1598         else
1599                 retstr = NULL;
1600         return retstr;
1601 }
1602
1603 #endif
1604
1605 static int
1606 SanityCheckInput(int ndim, int n, int *dim, int *lb, int *indx)
1607 {
1608         int                     i;
1609
1610         /* Do Sanity check on input */
1611         if (n != ndim)
1612                 return 0;
1613         for (i = 0; i < ndim; i++)
1614                 if ((lb[i] > indx[i]) || (indx[i] >= (dim[i] + lb[i])))
1615                         return 0;
1616         return 1;
1617 }
1618
1619 static void
1620 _ArrayRange(int *st,
1621                         int *endp,
1622                         int bsize,
1623                         char *destPtr,
1624                         ArrayType *array,
1625                         int from)
1626 {
1627         int                     n,
1628                            *dim,
1629                            *lb,
1630                                 st_pos,
1631                                 prod[MAXDIM];
1632         int                     span[MAXDIM],
1633                                 dist[MAXDIM],
1634                                 indx[MAXDIM];
1635         int                     i,
1636                                 j,
1637                                 inc;
1638         char       *srcPtr;
1639
1640         n = ARR_NDIM(array);
1641         dim = ARR_DIMS(array);
1642         lb = ARR_LBOUND(array);
1643         srcPtr = ARR_DATA_PTR(array);
1644         for (i = 0; i < n; st[i] -= lb[i], endp[i] -= lb[i], i++);
1645         mda_get_prod(n, dim, prod);
1646         st_pos = tuple2linear(n, st, prod);
1647         srcPtr = array_seek(srcPtr, bsize, st_pos);
1648         mda_get_range(n, span, st, endp);
1649         mda_get_offset_values(n, dist, prod, span);
1650         for (i = 0; i < n; indx[i++] = 0);
1651         i = j = n - 1;
1652         inc = bsize;
1653         do
1654         {
1655                 srcPtr = array_seek(srcPtr, bsize, dist[j]);
1656                 if (from)
1657                         inc = array_read(destPtr, bsize, 1, srcPtr);
1658                 else
1659                         inc = array_read(srcPtr, bsize, 1, destPtr);
1660                 destPtr += inc;
1661                 srcPtr += inc;
1662         } while ((j = next_tuple(i + 1, indx, span)) != -1);
1663 }
1664
1665 static int
1666 _ArrayClipCount(int *stI, int *endpI, ArrayType *array)
1667 {
1668         int                     n,
1669                            *dim,
1670                            *lb,
1671                                 st_pos,
1672                                 prod[MAXDIM];
1673         int                     span[MAXDIM],
1674                                 dist[MAXDIM],
1675                                 indx[MAXDIM];
1676         int                     i,
1677                                 j,
1678                                 inc,
1679                                 st[MAXDIM],
1680                                 endp[MAXDIM];
1681         int                     count = 0;
1682         char       *ptr;
1683
1684         n = ARR_NDIM(array);
1685         dim = ARR_DIMS(array);
1686         lb = ARR_LBOUND(array);
1687         ptr = ARR_DATA_PTR(array);
1688         for (i = 0; i < n; st[i] = stI[i] - lb[i], endp[i] = endpI[i] - lb[i], i++);
1689         mda_get_prod(n, dim, prod);
1690         st_pos = tuple2linear(n, st, prod);
1691         ptr = array_seek(ptr, -1, st_pos);
1692         mda_get_range(n, span, st, endp);
1693         mda_get_offset_values(n, dist, prod, span);
1694         for (i = 0; i < n; indx[i++] = 0);
1695         i = j = n - 1;
1696         do
1697         {
1698                 ptr = array_seek(ptr, -1, dist[j]);
1699                 inc = INTALIGN(*(int32 *) ptr);
1700                 ptr += inc;
1701                 count += inc;
1702         } while ((j = next_tuple(i + 1, indx, span)) != -1);
1703         return count;
1704 }
1705
1706 static char *
1707 array_seek(char *ptr, int eltsize, int nitems)
1708 {
1709         int                     i;
1710
1711         if (eltsize > 0)
1712                 return ptr + eltsize * nitems;
1713         for (i = 0; i < nitems; i++)
1714                 ptr += INTALIGN(*(int32 *) ptr);
1715         return ptr;
1716 }
1717
1718 static int
1719 array_read(char *destptr, int eltsize, int nitems, char *srcptr)
1720 {
1721         int                     i,
1722                                 inc,
1723                                 tmp;
1724
1725         if (eltsize > 0)
1726         {
1727                 memmove(destptr, srcptr, eltsize * nitems);
1728                 return eltsize * nitems;
1729         }
1730         for (i = inc = 0; i < nitems; i++)
1731         {
1732                 tmp = (INTALIGN(*(int32 *) srcptr));
1733                 memmove(destptr, srcptr, tmp);
1734                 srcptr += tmp;
1735                 destptr += tmp;
1736                 inc += tmp;
1737         }
1738         return inc;
1739 }
1740
1741 static void
1742 _LOArrayRange(int *st,
1743                           int *endp,
1744                           int bsize,
1745                           int srcfd,
1746                           int destfd,
1747                           ArrayType *array,
1748                           int isSrcLO,
1749                           bool *isNull)
1750 {
1751         int                     n,
1752                            *dim,
1753                                 st_pos,
1754                                 prod[MAXDIM];
1755         int                     span[MAXDIM],
1756                                 dist[MAXDIM],
1757                                 indx[MAXDIM];
1758         int                     i,
1759                                 j,
1760                                 inc,
1761                                 tmp,
1762                            *lb,
1763                                 offset;
1764
1765         n = ARR_NDIM(array);
1766         dim = ARR_DIMS(array);
1767         lb = ARR_LBOUND(array);
1768         for (i = 0; i < n; st[i] -= lb[i], endp[i] -= lb[i], i++);
1769
1770         mda_get_prod(n, dim, prod);
1771         st_pos = tuple2linear(n, st, prod);
1772         offset = st_pos * bsize;
1773         if (DatumGetInt32(DirectFunctionCall3(lo_lseek,
1774                                                           Int32GetDatum(srcfd),
1775                                                           Int32GetDatum(offset),
1776                                                           Int32GetDatum(SEEK_SET))) < 0)
1777                 return;
1778         mda_get_range(n, span, st, endp);
1779         mda_get_offset_values(n, dist, prod, span);
1780         for (i = 0; i < n; indx[i++] = 0);
1781         for (i = n - 1, inc = bsize; i >= 0; inc *= span[i--])
1782                 if (dist[i])
1783                         break;
1784         j = n - 1;
1785         do
1786         {
1787                 offset += (dist[j] * bsize);
1788                 if (DatumGetInt32(DirectFunctionCall3(lo_lseek,
1789                                                           Int32GetDatum(srcfd),
1790                                                           Int32GetDatum(offset),
1791                                                           Int32GetDatum(SEEK_SET))) < 0)
1792                         return;
1793                 tmp = _LOtransfer((char **) &srcfd, inc, 1, (char **) &destfd, isSrcLO, 1);
1794                 if (tmp < inc)
1795                         return;
1796                 offset += inc;
1797         } while ((j = next_tuple(i + 1, indx, span)) != -1);
1798 }
1799
1800
1801 static void
1802 _ReadArray(int *st,
1803                    int *endp,
1804                    int bsize,
1805                    int srcfd,
1806                    int destfd,
1807                    ArrayType *array,
1808                    int isDestLO,
1809                    bool *isNull)
1810 {
1811         int                     n,
1812                            *dim,
1813                                 st_pos,
1814                                 prod[MAXDIM];
1815         int                     span[MAXDIM],
1816                                 dist[MAXDIM],
1817                                 indx[MAXDIM];
1818         int                     i,
1819                                 j,
1820                                 inc,
1821                                 tmp,
1822                            *lb,
1823                                 offset;
1824
1825         n = ARR_NDIM(array);
1826         dim = ARR_DIMS(array);
1827         lb = ARR_LBOUND(array);
1828         for (i = 0; i < n; st[i] -= lb[i], endp[i] -= lb[i], i++);
1829
1830         mda_get_prod(n, dim, prod);
1831         st_pos = tuple2linear(n, st, prod);
1832         offset = st_pos * bsize;
1833         if (DatumGetInt32(DirectFunctionCall3(lo_lseek,
1834                                                           Int32GetDatum(srcfd),
1835                                                           Int32GetDatum(offset),
1836                                                           Int32GetDatum(SEEK_SET))) < 0)
1837                 return;
1838         mda_get_range(n, span, st, endp);
1839         mda_get_offset_values(n, dist, prod, span);
1840         for (i = 0; i < n; indx[i++] = 0);
1841         for (i = n - 1, inc = bsize; i >= 0; inc *= span[i--])
1842                 if (dist[i])
1843                         break;
1844         j = n - 1;
1845         do
1846         {
1847                 offset += (dist[j] * bsize);
1848                 if (DatumGetInt32(DirectFunctionCall3(lo_lseek,
1849                                                           Int32GetDatum(srcfd),
1850                                                           Int32GetDatum(offset),
1851                                                           Int32GetDatum(SEEK_SET))) < 0)
1852                         return;
1853                 tmp = _LOtransfer((char **) &destfd, inc, 1, (char **) &srcfd, 1, isDestLO);
1854                 if (tmp < inc)
1855                         return;
1856                 offset += inc;
1857         } while ((j = next_tuple(i + 1, indx, span)) != -1);
1858 }
1859
1860
1861 int
1862 _LOtransfer(char **destfd,
1863                         int size,
1864                         int nitems,
1865                         char **srcfd,
1866                         int isSrcLO,
1867                         int isDestLO)
1868 {
1869 #define MAX_READ (512 * 1024)
1870 #if !defined(min)
1871 #define min(a, b) (a < b ? a : b)
1872 #endif
1873         struct varlena *v = NULL;
1874         int                     tmp,
1875                                 inc,
1876                                 resid;
1877
1878         inc = nitems * size;
1879         if (isSrcLO && isDestLO && inc > 0)
1880                 for (tmp = 0, resid = inc;
1881                          resid > 0 && (inc = min(resid, MAX_READ)) > 0; resid -= inc)
1882                 {
1883 #ifdef LOARRAY
1884                         v = (struct varlena *)
1885                                 DatumGetPointer(DirectFunctionCall2(loread,
1886                                                                 Int32GetDatum((int32) *srcfd),
1887                                                                 Int32GetDatum(inc)));
1888                         if (VARSIZE(v) - VARHDRSZ < inc)
1889                         {
1890                                 pfree(v);
1891                                 return -1;
1892                         }
1893                         tmp += DatumGetInt32(DirectFunctionCall2(lowrite,
1894                                                                  Int32GetDatum((int32) *destfd),
1895                                                                  PointerGetDatum(v)));
1896 #endif
1897                         pfree(v);
1898
1899                 }
1900         else if (!isSrcLO && isDestLO)
1901         {
1902                 tmp = lo_write((int) *destfd, *srcfd, inc);
1903                 *srcfd = *srcfd + tmp;
1904         }
1905         else if (isSrcLO && !isDestLO)
1906         {
1907                 tmp = lo_read((int) *srcfd, *destfd, inc);
1908                 *destfd = *destfd + tmp;
1909         }
1910         else
1911         {
1912                 memmove(*destfd, *srcfd, inc);
1913                 tmp = inc;
1914                 *srcfd += inc;
1915                 *destfd += inc;
1916         }
1917         return tmp;
1918 #undef MAX_READ
1919 }
1920
1921 char *
1922 _array_newLO(int *fd, int flag)
1923 {
1924         char       *p;
1925         char            saveName[NAME_LEN];
1926
1927         p = (char *) palloc(NAME_LEN);
1928         sprintf(p, "/Arry.%u", newoid());
1929         strcpy(saveName, p);
1930 #ifdef LOARRAY
1931         if ((*fd = LOcreat(saveName, 0600, flag)) < 0)
1932                 elog(ERROR, "Large object create failed");
1933 #endif
1934         return p;
1935 }