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