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