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