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