]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/arrayfuncs.c
I had overlooked the fact that some fmgr-callable functions return void
[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.58 2000/06/14 05:24:48 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                 PG_RETURN_POINTER(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         PG_RETURN_POINTER(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 (ARR_IS_LO(v) == true)
626         {
627                 text       *p;
628                 int                     plen,
629                                         nbytes;
630
631                 p = (text *) DatumGetPointer(DirectFunctionCall1(array_dims,
632                                                                                                                  PointerGetDatum(v)));
633                 plen = VARSIZE(p) - VARHDRSZ;
634
635                 /* get a wide string to print to */
636                 nbytes = strlen(ARR_DATA_PTR(v)) + strlen(ASSGN) + plen + 1;
637                 retval = (char *) palloc(nbytes);
638
639                 memcpy(retval, VARDATA(p), plen);
640                 strcpy(retval + plen, ASSGN);
641                 strcat(retval, ARR_DATA_PTR(v));
642                 pfree(p);
643                 PG_RETURN_CSTRING(retval);
644         }
645
646         system_cache_lookup(element_type, false, &typlen, &typbyval,
647                                                 &typdelim, &typelem, &typoutput, &typalign);
648         fmgr_info(typoutput, &outputproc);
649         sprintf(delim, "%c", typdelim);
650         ndim = ARR_NDIM(v);
651         dim = ARR_DIMS(v);
652         nitems = getNitems(ndim, dim);
653
654         if (nitems == 0)
655         {
656                 retval = (char *) palloc(3);
657                 retval[0] = '{';
658                 retval[1] = '}';
659                 retval[2] = '\0';
660                 PG_RETURN_CSTRING(retval);
661         }
662
663         p = ARR_DATA_PTR(v);
664         overall_length = 1;                     /* [TRH] don't forget to count \0 at end. */
665         values = (char **) palloc(nitems * sizeof(char *));
666         for (i = 0; i < nitems; i++)
667         {
668                 if (typbyval)
669                 {
670                         switch (typlen)
671                         {
672                                 case 1:
673                                         values[i] = DatumGetCString(FunctionCall3(&outputproc,
674                                                                                                 CharGetDatum(*p),
675                                                                                                 ObjectIdGetDatum(typelem),
676                                                                                                 Int32GetDatum(-1)));
677                                         break;
678                                 case 2:
679                                         values[i] = DatumGetCString(FunctionCall3(&outputproc,
680                                                                                                 Int16GetDatum(*(int16 *) p),
681                                                                                                 ObjectIdGetDatum(typelem),
682                                                                                                 Int32GetDatum(-1)));
683                                         break;
684                                 case 3:
685                                 case 4:
686                                         values[i] = DatumGetCString(FunctionCall3(&outputproc,
687                                                                                                 Int32GetDatum(*(int32 *) p),
688                                                                                                 ObjectIdGetDatum(typelem),
689                                                                                                 Int32GetDatum(-1)));
690                                         break;
691                         }
692                         p += typlen;
693                 }
694                 else
695                 {
696                         values[i] = DatumGetCString(FunctionCall3(&outputproc,
697                                                                                                 PointerGetDatum(p),
698                                                                                                 ObjectIdGetDatum(typelem),
699                                                                                                 Int32GetDatum(-1)));
700                         if (typlen > 0)
701                                 p += typlen;
702                         else
703                                 p += INTALIGN(*(int32 *) p);
704
705                         /*
706                          * For the pair of double quotes
707                          */
708                         overall_length += 2;
709                 }
710                 for (tmp = values[i]; *tmp; tmp++)
711                 {
712                         overall_length += 1;
713 #ifndef TCL_ARRAYS
714                         if (*tmp == '"')
715                                 overall_length += 1;
716 #endif
717                 }
718                 overall_length += 1;
719         }
720
721         /*
722          * count total number of curly braces in output string
723          */
724         for (i = j = 0, k = 1; i < ndim; k *= dim[i++], j += k);
725
726         p = (char *) palloc(overall_length + 2 * j);
727         retval = p;
728
729         strcpy(p, "{");
730         for (i = 0; i < ndim; indx[i++] = 0);
731         j = 0;
732         k = 0;
733         do
734         {
735                 for (i = j; i < ndim - 1; i++)
736                         strcat(p, "{");
737
738                 /*
739                  * Surround anything that is not passed by value in double quotes.
740                  * See above for more details.
741                  */
742                 if (!typbyval)
743                 {
744                         strcat(p, "\"");
745 #ifndef TCL_ARRAYS
746                         l = strlen(p);
747                         for (tmp = values[k]; *tmp; tmp++)
748                         {
749                                 if (*tmp == '"')
750                                         p[l++] = '\\';
751                                 p[l++] = *tmp;
752                         }
753                         p[l] = '\0';
754 #else
755                         strcat(p, values[k]);
756 #endif
757                         strcat(p, "\"");
758                 }
759                 else
760                         strcat(p, values[k]);
761                 pfree(values[k++]);
762
763                 for (i = ndim - 1; i >= 0; i--)
764                 {
765                         indx[i] = (indx[i] + 1) % dim[i];
766                         if (indx[i])
767                         {
768                                 strcat(p, delim);
769                                 break;
770                         }
771                         else
772                                 strcat(p, "}");
773                 }
774                 j = i;
775         } while (j != -1);
776
777         pfree(values);
778         PG_RETURN_CSTRING(retval);
779 }
780
781 /*-----------------------------------------------------------------------------
782  * array_dims :
783  *                returns the dimensions of the array pointed to by "v", as a "text"
784  *----------------------------------------------------------------------------
785  */
786 Datum
787 array_dims(PG_FUNCTION_ARGS)
788 {
789         ArrayType  *v = (ArrayType *) PG_GETARG_VARLENA_P(0);
790         text       *result;
791         char       *p;
792         int                     nbytes,
793                                 i;
794         int                *dimv,
795                            *lb;
796
797         nbytes = ARR_NDIM(v) * 33 + 1;
798         /*
799          * 33 since we assume 15 digits per number + ':' +'[]'
800          *
801          * +1 allows for temp trailing null
802          */
803
804         result = (text *) palloc(nbytes + VARHDRSZ);
805         MemSet(result, 0, nbytes + VARHDRSZ);
806         p = VARDATA(result);
807
808         dimv = ARR_DIMS(v);
809         lb = ARR_LBOUND(v);
810
811         for (i = 0; i < ARR_NDIM(v); i++)
812         {
813                 sprintf(p, "[%d:%d]", lb[i], dimv[i] + lb[i] - 1);
814                 p += strlen(p);
815         }
816         VARSIZE(result) = strlen(VARDATA(result)) + VARHDRSZ;
817
818         PG_RETURN_TEXT_P(result);
819 }
820
821 /*---------------------------------------------------------------------------
822  * array_ref :
823  *        This routine takes an array pointer and an index array and returns
824  *        a pointer to the referred element if element is passed by
825  *        reference otherwise returns the value of the referred element.
826  *---------------------------------------------------------------------------
827  */
828 Datum
829 array_ref(ArrayType *array,
830                   int nSubscripts,
831                   int *indx,
832                   bool elmbyval,
833                   int elmlen,
834                   int arraylen,
835                   bool *isNull)
836 {
837         int                     i,
838                                 ndim,
839                            *dim,
840                            *lb,
841                                 offset,
842                                 nbytes;
843         struct varlena *v = NULL;
844         Datum           result;
845         char       *retval;
846
847         if (array == (ArrayType *) NULL)
848                 RETURN_NULL(Datum);
849         if (arraylen > 0)
850         {
851
852                 /*
853                  * fixed length arrays -- these are assumed to be 1-d
854                  */
855                 if (indx[0] * elmlen > arraylen)
856                         elog(ERROR, "array_ref: array bound exceeded");
857                 retval = (char *) array + indx[0] * elmlen;
858                 return _ArrayCast(retval, elmbyval, elmlen);
859         }
860         dim = ARR_DIMS(array);
861         lb = ARR_LBOUND(array);
862         ndim = ARR_NDIM(array);
863         nbytes = (*(int32 *) array) - ARR_OVERHEAD(ndim);
864
865         if (!SanityCheckInput(ndim, nSubscripts, dim, lb, indx))
866                 RETURN_NULL(Datum);
867
868         offset = GetOffset(nSubscripts, dim, lb, indx);
869
870         if (ARR_IS_LO(array))
871         {
872                 char       *lo_name;
873                 int                     fd = 0;
874
875                 /* We are assuming fixed element lengths here */
876                 offset *= elmlen;
877                 lo_name = (char *) ARR_DATA_PTR(array);
878 #ifdef LOARRAY
879                 if ((fd = LOopen(lo_name, ARR_IS_INV(array) ? INV_READ : O_RDONLY)) < 0)
880                         RETURN_NULL(Datum);
881 #endif
882                 if (ARR_IS_CHUNKED(array))
883                         v = _ReadChunkArray1El(indx, elmlen, fd, array, isNull);
884                 else
885                 {
886                         if (DatumGetInt32(DirectFunctionCall3(lo_lseek,
887                                                           Int32GetDatum(fd),
888                                                           Int32GetDatum(offset),
889                                                           Int32GetDatum(SEEK_SET))) < 0)
890                                 RETURN_NULL(Datum);
891 #ifdef LOARRAY
892                         v = (struct varlena *)
893                                 DatumGetPointer(DirectFunctionCall2(loread,
894                                                                                                         Int32GetDatum(fd),
895                                                                                                         Int32GetDatum(elmlen)));
896 #endif
897                 }
898                 if (*isNull)
899                         RETURN_NULL(Datum);
900                 if (VARSIZE(v) - VARHDRSZ < elmlen)
901                         RETURN_NULL(Datum);
902                 DirectFunctionCall1(lo_close, Int32GetDatum(fd));
903                 result = _ArrayCast((char *) VARDATA(v), elmbyval, elmlen);
904                 if (! elmbyval)
905                 {                                               /* not by value */
906                         char       *tempdata = palloc(elmlen);
907
908                         memmove(tempdata, DatumGetPointer(result), elmlen);
909                         result = PointerGetDatum(tempdata);
910                 }
911                 pfree(v);
912                 return result;
913         }
914
915         if (elmlen > 0)
916         {
917                 offset = offset * elmlen;
918                 /* off the end of the array */
919                 if (nbytes - offset < 1)
920                         RETURN_NULL(Datum);
921                 retval = ARR_DATA_PTR(array) + offset;
922                 return _ArrayCast(retval, elmbyval, elmlen);
923         }
924         else
925         {
926                 int                     bytes = nbytes;
927
928                 retval = ARR_DATA_PTR(array);
929                 i = 0;
930                 while (bytes > 0)
931                 {
932                         if (i == offset)
933                                 return PointerGetDatum(retval);
934                         bytes -= INTALIGN(*(int32 *) retval);
935                         retval += INTALIGN(*(int32 *) retval);
936                         i++;
937                 }
938                 RETURN_NULL(Datum);
939         }
940 }
941
942 /*-----------------------------------------------------------------------------
943  * array_clip :
944  *                This routine takes an array and a range of indices (upperIndex and
945  *                 lowerIndx), creates a new array structure for the referred elements
946  *                 and returns a pointer to it.
947  *-----------------------------------------------------------------------------
948  */
949 ArrayType *
950 array_clip(ArrayType *array,
951                    int nSubscripts,
952                    int *upperIndx,
953                    int *lowerIndx,
954                    bool elmbyval,
955                    int elmlen,
956                    bool *isNull)
957 {
958         int                     i,
959                                 ndim,
960                            *dim,
961                            *lb,
962                                 nbytes;
963         ArrayType  *newArr;
964         int                     bytes,
965                                 span[MAXDIM];
966
967         /* timer_start(); */
968         if (array == (ArrayType *) NULL)
969                 RETURN_NULL(ArrayType *);
970         dim = ARR_DIMS(array);
971         lb = ARR_LBOUND(array);
972         ndim = ARR_NDIM(array);
973         nbytes = (*(int32 *) array) - ARR_OVERHEAD(ndim);
974
975         if (!SanityCheckInput(ndim, nSubscripts, dim, lb, upperIndx) ||
976                 !SanityCheckInput(ndim, nSubscripts, dim, lb, lowerIndx))
977                 RETURN_NULL(ArrayType *);
978
979         for (i = 0; i < nSubscripts; i++)
980                 if (lowerIndx[i] > upperIndx[i])
981                         elog(ERROR, "lowerIndex cannot be larger than upperIndx");
982         mda_get_range(nSubscripts, span, lowerIndx, upperIndx);
983
984         if (ARR_IS_LO(array))
985         {
986 #ifdef LOARRAY
987                 char       *lo_name;
988
989 #endif
990                 char       *newname = NULL;
991                 int                     fd = 0,
992                                         newfd = 0,
993                                         isDestLO = true,
994                                         rsize;
995
996                 if (elmlen < 0)
997                         elog(ERROR, "array_clip: array of variable length objects not implemented");
998 #ifdef LOARRAY
999                 lo_name = (char *) ARR_DATA_PTR(array);
1000                 if ((fd = LOopen(lo_name, ARR_IS_INV(array) ? INV_READ : O_RDONLY)) < 0)
1001                         RETURN_NULL(ArrayType *);
1002                 newname = _array_newLO(&newfd, Unix);
1003 #endif
1004                 bytes = strlen(newname) + 1 + ARR_OVERHEAD(nSubscripts);
1005                 newArr = (ArrayType *) palloc(bytes);
1006                 memmove(newArr, array, sizeof(ArrayType));
1007                 memmove(newArr, &bytes, sizeof(int));
1008                 memmove(ARR_DIMS(newArr), span, nSubscripts * sizeof(int));
1009                 memmove(ARR_LBOUND(newArr), lowerIndx, nSubscripts * sizeof(int));
1010                 strcpy(ARR_DATA_PTR(newArr), newname);
1011
1012                 rsize = compute_size(lowerIndx, upperIndx, nSubscripts, elmlen);
1013                 if (rsize < MAX_BUFF_SIZE)
1014                 {
1015                         char       *buff;
1016
1017                         rsize += VARHDRSZ;
1018                         buff = palloc(rsize);
1019                         if (buff)
1020                                 isDestLO = false;
1021                         if (ARR_IS_CHUNKED(array))
1022                         {
1023                                 _ReadChunkArray(lowerIndx, upperIndx, elmlen, fd, &(buff[VARHDRSZ]),
1024                                                                 array, 0, isNull);
1025                         }
1026                         else
1027                         {
1028                                 _ReadArray(lowerIndx, upperIndx, elmlen, fd, (int) &(buff[VARHDRSZ]),
1029                                                    array,
1030                                                    0, isNull);
1031                         }
1032                         memmove(buff, &rsize, VARHDRSZ);
1033 #ifdef LOARRAY
1034                         if (!*isNull)
1035                                 bytes = DatumGetInt32(DirectFunctionCall2(lowrite,
1036                                                                           Int32GetDatum(newfd),
1037                                                                           PointerGetDatum(buff)));
1038 #endif
1039                         pfree(buff);
1040                 }
1041                 if (isDestLO)
1042                 {
1043                         if (ARR_IS_CHUNKED(array))
1044                         {
1045                                 _ReadChunkArray(lowerIndx, upperIndx, elmlen, fd, (char *) newfd, array,
1046                                                                 1, isNull);
1047                         }
1048                         else
1049                                 _ReadArray(lowerIndx, upperIndx, elmlen, fd, newfd, array, 1, isNull);
1050                 }
1051 #ifdef LOARRAY
1052                 LOclose(fd);
1053                 LOclose(newfd);
1054 #endif
1055                 if (*isNull)
1056                 {
1057                         pfree(newArr);
1058                         newArr = NULL;
1059                 }
1060                 /* timer_end(); */
1061                 return newArr;
1062         }
1063
1064         if (elmlen > 0)
1065         {
1066                 bytes = getNitems(nSubscripts, span);
1067                 bytes = bytes * elmlen + ARR_OVERHEAD(nSubscripts);
1068         }
1069         else
1070         {
1071                 bytes = _ArrayClipCount(lowerIndx, upperIndx, array);
1072                 bytes += ARR_OVERHEAD(nSubscripts);
1073         }
1074         newArr = (ArrayType *) palloc(bytes);
1075         memmove(newArr, array, sizeof(ArrayType));
1076         memmove(newArr, &bytes, sizeof(int));
1077         memmove(ARR_DIMS(newArr), span, nSubscripts * sizeof(int));
1078         memmove(ARR_LBOUND(newArr), lowerIndx, nSubscripts * sizeof(int));
1079         _ArrayRange(lowerIndx, upperIndx, elmlen, ARR_DATA_PTR(newArr), array, 1);
1080         return newArr;
1081 }
1082
1083 /*-----------------------------------------------------------------------------
1084  * array_set  :
1085  *                This routine sets the value of an array location (specified by
1086  *                an index array) to a new value specified by "dataValue".
1087  * result :
1088  *                returns a pointer to the modified array.
1089  *-----------------------------------------------------------------------------
1090  */
1091 ArrayType *
1092 array_set(ArrayType *array,
1093                   int nSubscripts,
1094                   int *indx,
1095                   Datum dataValue,
1096                   bool elmbyval,
1097                   int elmlen,
1098                   int arraylen,
1099                   bool *isNull)
1100 {
1101         int                     ndim,
1102                            *dim,
1103                            *lb,
1104                                 offset,
1105                                 nbytes;
1106         char       *pos;
1107
1108         if (array == (ArrayType *) NULL)
1109                 RETURN_NULL(ArrayType *);
1110         if (arraylen > 0)
1111         {
1112
1113                 /*
1114                  * fixed length arrays -- these are assumed to be 1-d
1115                  */
1116                 if (indx[0] * elmlen > arraylen)
1117                         elog(ERROR, "array_ref: array bound exceeded");
1118                 pos = (char *) array + indx[0] * elmlen;
1119                 ArrayCastAndSet(dataValue, elmbyval, elmlen, pos);
1120                 return array;
1121         }
1122         dim = ARR_DIMS(array);
1123         lb = ARR_LBOUND(array);
1124         ndim = ARR_NDIM(array);
1125         nbytes = (*(int32 *) array) - ARR_OVERHEAD(ndim);
1126
1127         if (!SanityCheckInput(ndim, nSubscripts, dim, lb, indx))
1128         {
1129                 elog(ERROR, "array_set: array bound exceeded");
1130                 return array;
1131         }
1132         offset = GetOffset(nSubscripts, dim, lb, indx);
1133
1134         if (ARR_IS_LO(array))
1135         {
1136                 int                     fd = 0;
1137                 struct varlena *v;
1138
1139                 /* We are assuming fixed element lengths here */
1140                 offset *= elmlen;
1141 #ifdef LOARRAY
1142                 char       *lo_name;
1143
1144                 lo_name = ARR_DATA_PTR(array);
1145                 if ((fd = LOopen(lo_name, ARR_IS_INV(array) ? INV_WRITE : O_WRONLY)) < 0)
1146                         return array;
1147 #endif
1148                 if (DatumGetInt32(DirectFunctionCall3(lo_lseek,
1149                                                           Int32GetDatum(fd),
1150                                                           Int32GetDatum(offset),
1151                                                           Int32GetDatum(SEEK_SET))) < 0)
1152                         return array;
1153                 v = (struct varlena *) palloc(elmlen + VARHDRSZ);
1154                 VARSIZE(v) = elmlen + VARHDRSZ;
1155                 ArrayCastAndSet(dataValue, elmbyval, elmlen, VARDATA(v));
1156 #ifdef LOARRAY
1157                 if (DatumGetInt32(DirectFunctionCall2(lowrite,
1158                                                                                           Int32GetDatum(fd),
1159                                                                                           PointerGetDatum(v)))
1160                         != elmlen)
1161                         RETURN_NULL(ArrayType *);
1162 #endif
1163                 pfree(v);
1164                 DirectFunctionCall1(lo_close, Int32GetDatum(fd));
1165                 return array;
1166         }
1167         if (elmlen > 0)
1168         {
1169                 offset = offset * elmlen;
1170                 /* off the end of the array */
1171                 if (nbytes - offset < 1)
1172                         return array;
1173                 pos = ARR_DATA_PTR(array) + offset;
1174         }
1175         else
1176         {
1177                 ArrayType  *newarray;
1178                 char       *elt_ptr;
1179                 int                     oldsize,
1180                                         newsize,
1181                                         oldlen,
1182                                         newlen,
1183                                         lth0,
1184                                         lth1,
1185                                         lth2;
1186
1187                 elt_ptr = array_seek(ARR_DATA_PTR(array), -1, offset);
1188                 oldlen = INTALIGN(*(int32 *) elt_ptr);
1189                 newlen = INTALIGN(*(int32 *) DatumGetPointer(dataValue));
1190
1191                 if (oldlen == newlen)
1192                 {
1193                         /* new element with same size, overwrite old data */
1194                         ArrayCastAndSet(dataValue, elmbyval, elmlen, elt_ptr);
1195                         return array;
1196                 }
1197
1198                 /* new element with different size, reallocate the array */
1199                 oldsize = array->size;
1200                 lth0 = ARR_OVERHEAD(nSubscripts);
1201                 lth1 = (int) (elt_ptr - ARR_DATA_PTR(array));
1202                 lth2 = (int) (oldsize - lth0 - lth1 - oldlen);
1203                 newsize = lth0 + lth1 + newlen + lth2;
1204
1205                 newarray = (ArrayType *) palloc(newsize);
1206                 memmove((char *) newarray, (char *) array, lth0 + lth1);
1207                 newarray->size = newsize;
1208                 newlen = ArrayCastAndSet(dataValue, elmbyval, elmlen,
1209                                                                  (char *) newarray + lth0 + lth1);
1210                 memmove((char *) newarray + lth0 + lth1 + newlen,
1211                                 (char *) array + lth0 + lth1 + oldlen, lth2);
1212
1213                 /* ??? who should free this storage ??? */
1214                 return newarray;
1215         }
1216         ArrayCastAndSet(dataValue, elmbyval, elmlen, pos);
1217         return array;
1218 }
1219
1220 /*----------------------------------------------------------------------------
1221  * array_assgn :
1222  *                This routine sets the value of a range of array locations (specified
1223  *                by upper and lower index values ) to new values passed as
1224  *                another array
1225  * result :
1226  *                returns a pointer to the modified array.
1227  *----------------------------------------------------------------------------
1228  */
1229 ArrayType *
1230 array_assgn(ArrayType *array,
1231                         int nSubscripts,
1232                         int *upperIndx,
1233                         int *lowerIndx,
1234                         ArrayType *newArr,
1235                         bool elmbyval,
1236                         int elmlen,
1237                         bool *isNull)
1238 {
1239         int                     i,
1240                                 ndim,
1241                            *dim,
1242                            *lb;
1243
1244         if (array == (ArrayType *) NULL)
1245                 RETURN_NULL(ArrayType *);
1246         if (elmlen < 0)
1247                 elog(ERROR, "array_assgn: updates on arrays of variable length elements not implemented");
1248
1249         dim = ARR_DIMS(array);
1250         lb = ARR_LBOUND(array);
1251         ndim = ARR_NDIM(array);
1252
1253         if (!SanityCheckInput(ndim, nSubscripts, dim, lb, upperIndx) ||
1254                 !SanityCheckInput(ndim, nSubscripts, dim, lb, lowerIndx))
1255                 RETURN_NULL(ArrayType *);
1256
1257         for (i = 0; i < nSubscripts; i++)
1258                 if (lowerIndx[i] > upperIndx[i])
1259                         elog(ERROR, "lowerIndex larger than upperIndx");
1260
1261         if (ARR_IS_LO(array))
1262         {
1263                 int                     fd = 0,
1264                                         newfd = 0;
1265
1266 #ifdef LOARRAY
1267                 char       *lo_name;
1268
1269                 lo_name = (char *) ARR_DATA_PTR(array);
1270                 if ((fd = LOopen(lo_name, ARR_IS_INV(array) ? INV_WRITE : O_WRONLY)) < 0)
1271                         return array;
1272 #endif
1273                 if (ARR_IS_LO(newArr))
1274                 {
1275 #ifdef LOARRAY
1276                         lo_name = (char *) ARR_DATA_PTR(newArr);
1277                         if ((newfd = LOopen(lo_name, ARR_IS_INV(newArr) ? INV_READ : O_RDONLY)) < 0)
1278                                 return array;
1279 #endif
1280                         _LOArrayRange(lowerIndx, upperIndx, elmlen, fd, newfd, array, 1, isNull);
1281                         DirectFunctionCall1(lo_close, Int32GetDatum(newfd));
1282                 }
1283                 else
1284                 {
1285                         _LOArrayRange(lowerIndx, upperIndx, elmlen, fd, (int) ARR_DATA_PTR(newArr),
1286                                                   array, 0, isNull);
1287                 }
1288                 DirectFunctionCall1(lo_close, Int32GetDatum(fd));
1289                 return array;
1290         }
1291         _ArrayRange(lowerIndx, upperIndx, elmlen, ARR_DATA_PTR(newArr), array, 0);
1292         return array;
1293 }
1294
1295 /*
1296  * array_map()
1297  *
1298  * Map an array through an arbitrary function.  Return a new array with
1299  * same dimensions and each source element transformed by fn().  Each
1300  * source element is passed as the first argument to fn(); additional
1301  * arguments to be passed to fn() can be specified by the caller.
1302  * The output array can have a different element type than the input.
1303  *
1304  * Parameters are:
1305  * * fcinfo: a function-call data structure pre-constructed by the caller
1306  *   to be ready to call the desired function, with everything except the
1307  *   first argument position filled in.  In particular, flinfo identifies
1308  *   the function fn(), and if nargs > 1 then argument positions after the
1309  *   first must be preset to the additional values to be passed.  The
1310  *   first argument position initially holds the input array value.
1311  * * inpType: OID of element type of input array.  This must be the same as,
1312  *   or binary-compatible with, the first argument type of fn().
1313  * * retType: OID of element type of output array.  This must be the same as,
1314  *   or binary-compatible with, the result type of fn().
1315  *
1316  * NB: caller must assure that input array is not NULL.  Currently,
1317  * any additional parameters passed to fn() may not be specified as NULL
1318  * either.
1319  */
1320 Datum
1321 array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType)
1322 {
1323         ArrayType  *v;
1324         ArrayType  *result;
1325         char      **values;
1326         char       *elt;
1327         int                *dim;
1328         int                     ndim;
1329         int                     nitems;
1330         int                     i;
1331         int                     nbytes = 0;
1332         int                     inp_typlen;
1333         bool            inp_typbyval;
1334         int                     typlen;
1335         bool            typbyval;
1336         char            typdelim;
1337         Oid                     typelem;
1338         Oid                     proc;
1339         char            typalign;
1340         char       *s;
1341         char       *p;
1342
1343         /* Get input array */
1344         if (fcinfo->nargs < 1)
1345                 elog(ERROR, "array_map: invalid nargs: %d", fcinfo->nargs);
1346         if (PG_ARGISNULL(0))
1347                 elog(ERROR, "array_map: null input array");
1348         v = (ArrayType *) PG_GETARG_VARLENA_P(0);
1349
1350         /* Large objects not yet supported */
1351         if (ARR_IS_LO(v) == true)
1352                 elog(ERROR, "array_map: large objects not supported");
1353
1354         ndim = ARR_NDIM(v);
1355         dim = ARR_DIMS(v);
1356         nitems = getNitems(ndim, dim);
1357
1358         /* Check for empty array */
1359         if (nitems <= 0)
1360                 PG_RETURN_POINTER(v);
1361
1362         /* Lookup source and result types. Unneeded variables are reused. */
1363         system_cache_lookup(inpType, false, &inp_typlen, &inp_typbyval,
1364                                                 &typdelim, &typelem, &proc, &typalign);
1365         system_cache_lookup(retType, false, &typlen, &typbyval,
1366                                                 &typdelim, &typelem, &proc, &typalign);
1367
1368         /* Allocate temporary array for new values */
1369         values = (char **) palloc(nitems * sizeof(char *));
1370         MemSet(values, 0, nitems * sizeof(char *));
1371
1372         /* Loop over source data */
1373         s = (char *) ARR_DATA_PTR(v);
1374         for (i = 0; i < nitems; i++)
1375         {
1376                 /* Get source element */
1377                 if (inp_typbyval)
1378                 {
1379                         switch (inp_typlen)
1380                         {
1381                                 case 1:
1382                                         elt = (char *) ((int) (*(char *) s));
1383                                         break;
1384                                 case 2:
1385                                         elt = (char *) ((int) (*(int16 *) s));
1386                                         break;
1387                                 case 3:
1388                                 case 4:
1389                                 default:
1390                                         elt = (char *) (*(int32 *) s);
1391                                         break;
1392                         }
1393                         s += inp_typlen;
1394                 }
1395                 else
1396                 {
1397                         elt = s;
1398                         if (inp_typlen > 0)
1399                                 s += inp_typlen;
1400                         else
1401                                 s += INTALIGN(*(int32 *) s);
1402                 }
1403
1404                 /*
1405                  * Apply the given function to source elt and extra args.
1406                  *
1407                  * We assume the extra args are non-NULL, so need not check
1408                  * whether fn() is strict.  Would need to do more work here
1409                  * to support arrays containing nulls, too.
1410                  */
1411                 fcinfo->arg[0] = (Datum) elt;
1412                 fcinfo->argnull[0] = false;
1413                 fcinfo->isnull = false;
1414                 p = (char *) FunctionCallInvoke(fcinfo);
1415                 if (fcinfo->isnull)
1416                         elog(ERROR, "array_map: cannot handle NULL in array");
1417
1418                 /* Update values and total result size */
1419                 if (typbyval)
1420                 {
1421                         values[i] = p;
1422                         nbytes += typlen;
1423                 }
1424                 else
1425                 {
1426                         int                     len;
1427
1428                         len = ((typlen > 0) ? typlen : INTALIGN(*(int32 *) p));
1429                         /* Needed because _CopyArrayEls tries to pfree items */
1430                         if (p == elt)
1431                         {
1432                                 p = (char *) palloc(len);
1433                                 memcpy(p, elt, len);
1434                         }
1435                         values[i] = p;
1436                         nbytes += len;
1437                 }
1438         }
1439
1440         /* Allocate and initialize the result array */
1441         nbytes += ARR_OVERHEAD(ndim);
1442         result = (ArrayType *) palloc(nbytes);
1443         MemSet(result, 0, nbytes);
1444
1445         memcpy((char *) result, (char *) &nbytes, sizeof(int));
1446         memcpy((char *) ARR_NDIM_PTR(result), (char *) &ndim, sizeof(int));
1447         memcpy((char *) ARR_DIMS(result), ARR_DIMS(v), 2 * ndim * sizeof(int));
1448
1449         /* Copy new values into the result array. values is pfreed. */
1450         _CopyArrayEls((char **) values,
1451                                   ARR_DATA_PTR(result), nitems,
1452                                   typlen, typalign, typbyval);
1453
1454         PG_RETURN_POINTER(result);
1455 }
1456
1457 /*-----------------------------------------------------------------------------
1458  * array_eq :
1459  *                compares two arrays for equality
1460  * result :
1461  *                returns true if the arrays are equal, false otherwise.
1462  *-----------------------------------------------------------------------------
1463  */
1464 Datum
1465 array_eq(PG_FUNCTION_ARGS)
1466 {
1467         ArrayType  *array1 = (ArrayType *) PG_GETARG_VARLENA_P(0);
1468         ArrayType  *array2 = (ArrayType *) PG_GETARG_VARLENA_P(1);
1469
1470         if (*(int32 *) array1 != *(int32 *) array2)
1471                 PG_RETURN_BOOL(false);
1472         if (memcmp(array1, array2, *(int32 *) array1) != 0)
1473                 PG_RETURN_BOOL(false);
1474         PG_RETURN_BOOL(true);
1475 }
1476
1477 /***************************************************************************/
1478 /******************|              Support  Routines                       |*****************/
1479 /***************************************************************************/
1480 static void
1481 system_cache_lookup(Oid element_type,
1482                                         bool input,
1483                                         int *typlen,
1484                                         bool *typbyval,
1485                                         char *typdelim,
1486                                         Oid *typelem,
1487                                         Oid *proc,
1488                                         char *typalign)
1489 {
1490         HeapTuple       typeTuple;
1491         Form_pg_type typeStruct;
1492
1493         typeTuple = SearchSysCacheTuple(TYPEOID,
1494                                                                         ObjectIdGetDatum(element_type),
1495                                                                         0, 0, 0);
1496
1497         if (!HeapTupleIsValid(typeTuple))
1498         {
1499                 elog(ERROR, "array_out: Cache lookup failed for type %u\n",
1500                          element_type);
1501                 return;
1502         }
1503         typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
1504         *typlen = typeStruct->typlen;
1505         *typbyval = typeStruct->typbyval;
1506         *typdelim = typeStruct->typdelim;
1507         *typelem = typeStruct->typelem;
1508         *typalign = typeStruct->typalign;
1509         if (input)
1510                 *proc = typeStruct->typinput;
1511         else
1512                 *proc = typeStruct->typoutput;
1513 }
1514
1515 static Datum
1516 _ArrayCast(char *value, bool byval, int len)
1517 {
1518         if (byval)
1519         {
1520                 switch (len)
1521                 {
1522                                 case 1:
1523                                 return (Datum) *value;
1524                         case 2:
1525                                 return (Datum) *(int16 *) value;
1526                         case 3:
1527                         case 4:
1528                                 return (Datum) *(int32 *) value;
1529                         default:
1530                                 elog(ERROR, "array_ref: byval and elt len > 4!");
1531                                 break;
1532                 }
1533         }
1534         else
1535                 return (Datum) value;
1536         return 0;
1537 }
1538
1539
1540 static int
1541 ArrayCastAndSet(Datum src,
1542                                 bool typbyval,
1543                                 int typlen,
1544                                 char *dest)
1545 {
1546         int                     inc;
1547
1548         if (typlen > 0)
1549         {
1550                 if (typbyval)
1551                 {
1552                         switch (typlen)
1553                         {
1554                                 case 1:
1555                                         *dest = DatumGetChar(src);
1556                                         break;
1557                                 case 2:
1558                                         *(int16 *) dest = DatumGetInt16(src);
1559                                         break;
1560                                 case 4:
1561                                         *(int32 *) dest = DatumGetInt32(src);
1562                                         break;
1563                         }
1564                 }
1565                 else
1566                         memmove(dest, DatumGetPointer(src), typlen);
1567                 inc = typlen;
1568         }
1569         else
1570         {
1571                 memmove(dest, DatumGetPointer(src), *(int32 *) DatumGetPointer(src));
1572                 inc = (INTALIGN(*(int32 *) DatumGetPointer(src)));
1573         }
1574         return inc;
1575 }
1576
1577 #ifdef LOARRAY
1578 static char *
1579 _AdvanceBy1word(char *str, char **word)
1580 {
1581         char       *retstr,
1582                            *space;
1583
1584         *word = NULL;
1585         if (str == NULL)
1586                 return str;
1587         while (isspace(*str))
1588                 str++;
1589         *word = str;
1590         if ((space = (char *) strchr(str, ' ')) != (char *) NULL)
1591         {
1592                 retstr = space + 1;
1593                 *space = '\0';
1594         }
1595         else
1596                 retstr = NULL;
1597         return retstr;
1598 }
1599
1600 #endif
1601
1602 static int
1603 SanityCheckInput(int ndim, int n, int *dim, int *lb, int *indx)
1604 {
1605         int                     i;
1606
1607         /* Do Sanity check on input */
1608         if (n != ndim)
1609                 return 0;
1610         for (i = 0; i < ndim; i++)
1611                 if ((lb[i] > indx[i]) || (indx[i] >= (dim[i] + lb[i])))
1612                         return 0;
1613         return 1;
1614 }
1615
1616 static void
1617 _ArrayRange(int *st,
1618                         int *endp,
1619                         int bsize,
1620                         char *destPtr,
1621                         ArrayType *array,
1622                         int from)
1623 {
1624         int                     n,
1625                            *dim,
1626                            *lb,
1627                                 st_pos,
1628                                 prod[MAXDIM];
1629         int                     span[MAXDIM],
1630                                 dist[MAXDIM],
1631                                 indx[MAXDIM];
1632         int                     i,
1633                                 j,
1634                                 inc;
1635         char       *srcPtr;
1636
1637         n = ARR_NDIM(array);
1638         dim = ARR_DIMS(array);
1639         lb = ARR_LBOUND(array);
1640         srcPtr = ARR_DATA_PTR(array);
1641         for (i = 0; i < n; st[i] -= lb[i], endp[i] -= lb[i], i++);
1642         mda_get_prod(n, dim, prod);
1643         st_pos = tuple2linear(n, st, prod);
1644         srcPtr = array_seek(srcPtr, bsize, st_pos);
1645         mda_get_range(n, span, st, endp);
1646         mda_get_offset_values(n, dist, prod, span);
1647         for (i = 0; i < n; indx[i++] = 0);
1648         i = j = n - 1;
1649         inc = bsize;
1650         do
1651         {
1652                 srcPtr = array_seek(srcPtr, bsize, dist[j]);
1653                 if (from)
1654                         inc = array_read(destPtr, bsize, 1, srcPtr);
1655                 else
1656                         inc = array_read(srcPtr, bsize, 1, destPtr);
1657                 destPtr += inc;
1658                 srcPtr += inc;
1659         } while ((j = next_tuple(i + 1, indx, span)) != -1);
1660 }
1661
1662 static int
1663 _ArrayClipCount(int *stI, int *endpI, ArrayType *array)
1664 {
1665         int                     n,
1666                            *dim,
1667                            *lb,
1668                                 st_pos,
1669                                 prod[MAXDIM];
1670         int                     span[MAXDIM],
1671                                 dist[MAXDIM],
1672                                 indx[MAXDIM];
1673         int                     i,
1674                                 j,
1675                                 inc,
1676                                 st[MAXDIM],
1677                                 endp[MAXDIM];
1678         int                     count = 0;
1679         char       *ptr;
1680
1681         n = ARR_NDIM(array);
1682         dim = ARR_DIMS(array);
1683         lb = ARR_LBOUND(array);
1684         ptr = ARR_DATA_PTR(array);
1685         for (i = 0; i < n; st[i] = stI[i] - lb[i], endp[i] = endpI[i] - lb[i], i++);
1686         mda_get_prod(n, dim, prod);
1687         st_pos = tuple2linear(n, st, prod);
1688         ptr = array_seek(ptr, -1, st_pos);
1689         mda_get_range(n, span, st, endp);
1690         mda_get_offset_values(n, dist, prod, span);
1691         for (i = 0; i < n; indx[i++] = 0);
1692         i = j = n - 1;
1693         do
1694         {
1695                 ptr = array_seek(ptr, -1, dist[j]);
1696                 inc = INTALIGN(*(int32 *) ptr);
1697                 ptr += inc;
1698                 count += inc;
1699         } while ((j = next_tuple(i + 1, indx, span)) != -1);
1700         return count;
1701 }
1702
1703 static char *
1704 array_seek(char *ptr, int eltsize, int nitems)
1705 {
1706         int                     i;
1707
1708         if (eltsize > 0)
1709                 return ptr + eltsize * nitems;
1710         for (i = 0; i < nitems; i++)
1711                 ptr += INTALIGN(*(int32 *) ptr);
1712         return ptr;
1713 }
1714
1715 static int
1716 array_read(char *destptr, int eltsize, int nitems, char *srcptr)
1717 {
1718         int                     i,
1719                                 inc,
1720                                 tmp;
1721
1722         if (eltsize > 0)
1723         {
1724                 memmove(destptr, srcptr, eltsize * nitems);
1725                 return eltsize * nitems;
1726         }
1727         for (i = inc = 0; i < nitems; i++)
1728         {
1729                 tmp = (INTALIGN(*(int32 *) srcptr));
1730                 memmove(destptr, srcptr, tmp);
1731                 srcptr += tmp;
1732                 destptr += tmp;
1733                 inc += tmp;
1734         }
1735         return inc;
1736 }
1737
1738 static void
1739 _LOArrayRange(int *st,
1740                           int *endp,
1741                           int bsize,
1742                           int srcfd,
1743                           int destfd,
1744                           ArrayType *array,
1745                           int isSrcLO,
1746                           bool *isNull)
1747 {
1748         int                     n,
1749                            *dim,
1750                                 st_pos,
1751                                 prod[MAXDIM];
1752         int                     span[MAXDIM],
1753                                 dist[MAXDIM],
1754                                 indx[MAXDIM];
1755         int                     i,
1756                                 j,
1757                                 inc,
1758                                 tmp,
1759                            *lb,
1760                                 offset;
1761
1762         n = ARR_NDIM(array);
1763         dim = ARR_DIMS(array);
1764         lb = ARR_LBOUND(array);
1765         for (i = 0; i < n; st[i] -= lb[i], endp[i] -= lb[i], i++);
1766
1767         mda_get_prod(n, dim, prod);
1768         st_pos = tuple2linear(n, st, prod);
1769         offset = st_pos * bsize;
1770         if (DatumGetInt32(DirectFunctionCall3(lo_lseek,
1771                                                           Int32GetDatum(srcfd),
1772                                                           Int32GetDatum(offset),
1773                                                           Int32GetDatum(SEEK_SET))) < 0)
1774                 return;
1775         mda_get_range(n, span, st, endp);
1776         mda_get_offset_values(n, dist, prod, span);
1777         for (i = 0; i < n; indx[i++] = 0);
1778         for (i = n - 1, inc = bsize; i >= 0; inc *= span[i--])
1779                 if (dist[i])
1780                         break;
1781         j = n - 1;
1782         do
1783         {
1784                 offset += (dist[j] * bsize);
1785                 if (DatumGetInt32(DirectFunctionCall3(lo_lseek,
1786                                                           Int32GetDatum(srcfd),
1787                                                           Int32GetDatum(offset),
1788                                                           Int32GetDatum(SEEK_SET))) < 0)
1789                         return;
1790                 tmp = _LOtransfer((char **) &srcfd, inc, 1, (char **) &destfd, isSrcLO, 1);
1791                 if (tmp < inc)
1792                         return;
1793                 offset += inc;
1794         } while ((j = next_tuple(i + 1, indx, span)) != -1);
1795 }
1796
1797
1798 static void
1799 _ReadArray(int *st,
1800                    int *endp,
1801                    int bsize,
1802                    int srcfd,
1803                    int destfd,
1804                    ArrayType *array,
1805                    int isDestLO,
1806                    bool *isNull)
1807 {
1808         int                     n,
1809                            *dim,
1810                                 st_pos,
1811                                 prod[MAXDIM];
1812         int                     span[MAXDIM],
1813                                 dist[MAXDIM],
1814                                 indx[MAXDIM];
1815         int                     i,
1816                                 j,
1817                                 inc,
1818                                 tmp,
1819                            *lb,
1820                                 offset;
1821
1822         n = ARR_NDIM(array);
1823         dim = ARR_DIMS(array);
1824         lb = ARR_LBOUND(array);
1825         for (i = 0; i < n; st[i] -= lb[i], endp[i] -= lb[i], i++);
1826
1827         mda_get_prod(n, dim, prod);
1828         st_pos = tuple2linear(n, st, prod);
1829         offset = st_pos * bsize;
1830         if (DatumGetInt32(DirectFunctionCall3(lo_lseek,
1831                                                           Int32GetDatum(srcfd),
1832                                                           Int32GetDatum(offset),
1833                                                           Int32GetDatum(SEEK_SET))) < 0)
1834                 return;
1835         mda_get_range(n, span, st, endp);
1836         mda_get_offset_values(n, dist, prod, span);
1837         for (i = 0; i < n; indx[i++] = 0);
1838         for (i = n - 1, inc = bsize; i >= 0; inc *= span[i--])
1839                 if (dist[i])
1840                         break;
1841         j = n - 1;
1842         do
1843         {
1844                 offset += (dist[j] * bsize);
1845                 if (DatumGetInt32(DirectFunctionCall3(lo_lseek,
1846                                                           Int32GetDatum(srcfd),
1847                                                           Int32GetDatum(offset),
1848                                                           Int32GetDatum(SEEK_SET))) < 0)
1849                         return;
1850                 tmp = _LOtransfer((char **) &destfd, inc, 1, (char **) &srcfd, 1, isDestLO);
1851                 if (tmp < inc)
1852                         return;
1853                 offset += inc;
1854         } while ((j = next_tuple(i + 1, indx, span)) != -1);
1855 }
1856
1857
1858 int
1859 _LOtransfer(char **destfd,
1860                         int size,
1861                         int nitems,
1862                         char **srcfd,
1863                         int isSrcLO,
1864                         int isDestLO)
1865 {
1866 #define MAX_READ (512 * 1024)
1867 #if !defined(min)
1868 #define min(a, b) (a < b ? a : b)
1869 #endif
1870         struct varlena *v = NULL;
1871         int                     tmp,
1872                                 inc,
1873                                 resid;
1874
1875         inc = nitems * size;
1876         if (isSrcLO && isDestLO && inc > 0)
1877                 for (tmp = 0, resid = inc;
1878                          resid > 0 && (inc = min(resid, MAX_READ)) > 0; resid -= inc)
1879                 {
1880 #ifdef LOARRAY
1881                         v = (struct varlena *)
1882                                 DatumGetPointer(DirectFunctionCall2(loread,
1883                                                                 Int32GetDatum((int32) *srcfd),
1884                                                                 Int32GetDatum(inc)));
1885                         if (VARSIZE(v) - VARHDRSZ < inc)
1886                         {
1887                                 pfree(v);
1888                                 return -1;
1889                         }
1890                         tmp += DatumGetInt32(DirectFunctionCall2(lowrite,
1891                                                                  Int32GetDatum((int32) *destfd),
1892                                                                  PointerGetDatum(v)));
1893 #endif
1894                         pfree(v);
1895
1896                 }
1897         else if (!isSrcLO && isDestLO)
1898         {
1899                 tmp = lo_write((int) *destfd, *srcfd, inc);
1900                 *srcfd = *srcfd + tmp;
1901         }
1902         else if (isSrcLO && !isDestLO)
1903         {
1904                 tmp = lo_read((int) *srcfd, *destfd, inc);
1905                 *destfd = *destfd + tmp;
1906         }
1907         else
1908         {
1909                 memmove(*destfd, *srcfd, inc);
1910                 tmp = inc;
1911                 *srcfd += inc;
1912                 *destfd += inc;
1913         }
1914         return tmp;
1915 #undef MAX_READ
1916 }
1917
1918 char *
1919 _array_newLO(int *fd, int flag)
1920 {
1921         char       *p;
1922         char            saveName[NAME_LEN];
1923
1924         p = (char *) palloc(NAME_LEN);
1925         sprintf(p, "/Arry.%u", newoid());
1926         strcpy(saveName, p);
1927 #ifdef LOARRAY
1928         if ((*fd = LOcreat(saveName, 0600, flag)) < 0)
1929                 elog(ERROR, "Large object create failed");
1930 #endif
1931         return p;
1932 }