1 /*-------------------------------------------------------------------------
4 * Special functions for arrays.
6 * Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.29 1998/03/30 16:47:23 momjian Exp $
12 *-------------------------------------------------------------------------
21 #include "catalog/catalog.h"
22 #include "catalog/pg_type.h"
24 #include "utils/syscache.h"
25 #include "utils/memutils.h"
26 #include "storage/fd.h"
28 #include "utils/array.h"
30 #include "libpq/libpq-fs.h"
31 #include "libpq/be-fsstubs.h"
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
44 /*-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-*/
45 static int _ArrayCount(char *str, int dim[], int typdelim);
47 _ReadArrayStr(char *arrayStr, int nitems, int ndim, int dim[],
48 FmgrInfo *inputproc, Oid typelem, int16 typmod,
49 char typdelim, int typlen, bool typbyval,
50 char typalign, int *nbytes);
54 _ReadLOArray(char *str, int *nbytes, int *fd, bool *chunkFlag,
55 int ndim, int dim[], int baseSize);
59 _CopyArrayEls(char **values, char *p, int nitems, int typlen,
60 char typalign, bool typbyval);
62 system_cache_lookup(Oid element_type, bool input, int *typlen,
63 bool *typbyval, char *typdelim, Oid *typelem, Oid *proc,
65 static Datum _ArrayCast(char *value, bool byval, int len);
68 static char *_AdvanceBy1word(char *str, char **word);
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);
76 _LOArrayRange(int st[], int endp[], int bsize, int srcfd,
77 int destfd, ArrayType *array, int isSrcLO, bool *isNull);
79 _ReadArray(int st[], int endp[], int bsize, int srcfd, int destfd,
80 ArrayType *array, int isDestLO, bool *isNull);
81 static int ArrayCastAndSet(char *src, bool typbyval, int typlen, char *dest);
82 static int 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);
86 /*---------------------------------------------------------------------
88 * converts an array from the external format in "string" to
91 * the internal representation of the input array
92 *--------------------------------------------------------------------
95 array_in(char *string, /* input array in external form */
96 Oid element_type, /* type OID of an array element */
114 ArrayType *retval = NULL;
120 system_cache_lookup(element_type, true, &typlen, &typbyval, &typdelim,
121 &typelem, &typinput, &typalign);
123 fmgr_info(typinput, &inputproc);
125 string_save = (char *) palloc(strlen(string) + 3);
126 strcpy(string_save, string);
128 /* --- read array dimensions ---------- */
131 for (ndim = 0; !done;)
138 if ((r = (char *) strchr(p, ':')) == (char *) NULL)
143 lBound[ndim] = atoi(p);
146 for (q = p; isdigit(*q); q++);
148 elog(ERROR, "array_in: missing ']' in array declaration");
151 if ((dim[ndim] < 0) || (lBound[ndim] < 0))
152 elog(ERROR, "array_in: array dimensions need to be positive");
153 dim[ndim] = dim[ndim] - lBound[ndim] + 1;
155 elog(ERROR, "array_in: upper_bound cannot be < lower_bound");
169 ndim = _ArrayCount(p, dim, typdelim);
170 for (i = 0; i < ndim; lBound[i++] = 1);
174 elog(ERROR, "array_in: Need to specify dimension");
181 if (strncmp(p, ASSGN, strlen(ASSGN)))
182 elog(ERROR, "array_in: missing assignment operator");
189 printf("array_in- ndim %d (", ndim);
190 for (i = 0; i < ndim; i++)
192 printf(" %d", dim[i]);
194 printf(") for %s\n", string);
197 nitems = getNitems(ndim, dim);
200 char *emptyArray = palloc(sizeof(ArrayType));
202 MemSet(emptyArray, 0, sizeof(ArrayType));
203 *(int32 *) emptyArray = sizeof(ArrayType);
209 /* array not a large object */
211 (char *) _ReadArrayStr(p, nitems, ndim, dim, &inputproc, typelem,
212 typmod, typdelim, typlen, typbyval, typalign,
214 nbytes += ARR_OVERHEAD(ndim);
215 retval = (ArrayType *) palloc(nbytes);
216 MemSet(retval, 0, nbytes);
217 memmove(retval, (char *) &nbytes, sizeof(int));
218 memmove((char *) ARR_NDIM_PTR(retval), (char *) &ndim, sizeof(int));
219 SET_LO_FLAG(false, retval);
220 memmove((char *) ARR_DIMS(retval), (char *) dim, ndim * sizeof(int));
221 memmove((char *) ARR_LBOUND(retval), (char *) lBound,
225 * dataPtr is an array of arbitraystuff even though its type is
226 * char* cast to char** to pass to _CopyArrayEls for now - jolly
228 _CopyArrayEls((char **) dataPtr,
229 ARR_DATA_PTR(retval), nitems,
230 typlen, typalign, typbyval);
237 bool chunked = false;
239 dataPtr = _ReadLOArray(p, &bytes, &dummy, &chunked, ndim,
241 nbytes = bytes + ARR_OVERHEAD(ndim);
242 retval = (ArrayType *) palloc(nbytes);
243 MemSet(retval, 0, nbytes);
244 memmove(retval, (char *) &nbytes, sizeof(int));
245 memmove((char *) ARR_NDIM_PTR(retval), (char *) &ndim, sizeof(int));
246 SET_LO_FLAG(true, retval);
247 SET_CHUNK_FLAG(chunked, retval);
248 memmove((char *) ARR_DIMS(retval), (char *) dim, ndim * sizeof(int));
249 memmove((char *) ARR_LBOUND(retval), (char *) lBound, ndim * sizeof(int));
250 memmove(ARR_DATA_PTR(retval), dataPtr, bytes);
252 elog(ERROR, "large object arrays not supported");
255 return ((char *) retval);
258 /*-----------------------------------------------------------------------------
260 * Counts the number of dimensions and the dim[] array for an array string.
261 * The syntax for array input is C-like nested curly braces
262 *-----------------------------------------------------------------------------
265 _ArrayCount(char *str, int dim[], int typdelim)
271 bool scanning_string = false;
272 bool eoArray = false;
275 for (i = 0; i < MAXDIM; ++i)
277 temp[i] = dim[i] = 0;
280 if (strncmp(str, "{}", 2) == 0)
284 while (eoArray != true)
293 /* skip escaped characters (\ and ") inside strings */
294 if (scanning_string && *(q + 1))
302 * Signal a premature end of the string. DZ -
305 elog(ERROR, "malformed array constant: %s", str);
308 scanning_string = !scanning_string;
311 if (!scanning_string)
313 temp[nest_level] = 0;
318 if (!scanning_string)
324 temp[nest_level - 1]++;
326 eoArray = done = true;
332 if (*q == typdelim && !scanning_string)
345 for (i = 0; i < ndim; ++i)
353 /*---------------------------------------------------------------------------
355 * parses the array string pointed by "arrayStr" and converts it in the
356 * internal format. The external format expected is like C array
357 * declaration. Unspecified elements are initialized to zero for fixed length
358 * base types and to empty varlena structures for variable length base
361 * returns the internal representation of the array elements
362 * nbytes is set to the size of the array in its internal representation.
363 *---------------------------------------------------------------------------
366 _ReadArrayStr(char *arrayStr,
370 FmgrInfo *inputproc, /* function used for the
386 bool scanning_string = false;
389 bool eoArray = false;
391 mda_get_prod(ndim, dim, prod);
392 for (i = 0; i < ndim; indx[i++] = 0);
393 /* read array enclosed within {} */
394 values = (char **) palloc(nitems * sizeof(char *));
395 MemSet(values, 0, nitems * sizeof(char *));
408 /* Crunch the string on top of the backslash. */
409 for (r = q; *r != '\0'; r++)
413 if (!scanning_string)
417 p++; /* get p past first doublequote */
421 scanning_string = !scanning_string;
424 if (!scanning_string)
428 if (nest_level > ndim)
429 elog(ERROR, "array_in: illformed array constant");
430 indx[nest_level - 1] = 0;
435 if (!scanning_string)
438 i = tuple2linear(ndim, indx, prod);
441 eoArray = done = true;
445 indx[nest_level - 1]++;
450 if (*q == typdelim && !scanning_string)
453 i = tuple2linear(ndim, indx, prod);
464 elog(ERROR, "array_in: illformed array constant");
465 values[i] = (*fmgr_faddr(inputproc)) (p, typelem, typmod);
470 * if not at the end of the array skip white space
480 *nbytes = nitems * typlen;
482 for (i = 0; i < nitems; i++)
485 values[i] = palloc(typlen);
486 MemSet(values[i], 0, typlen);
491 for (i = 0, *nbytes = 0; i < nitems; i++)
497 *nbytes += DOUBLEALIGN(*(int32 *) values[i]);
501 *nbytes += INTALIGN(*(int32 *) values[i]);
506 *nbytes += sizeof(int32);
507 values[i] = palloc(sizeof(int32));
508 *(int32 *) values[i] = sizeof(int32);
512 return ((char *) values);
516 /*----------------------------------------------------------------------------
517 * Read data about an array to be stored as a large object
518 *----------------------------------------------------------------------------
522 _ReadLOArray(char *str,
537 str = _AdvanceBy1word(str, &inputfile);
543 str = _AdvanceBy1word(str, &word);
545 if (!strcmp(word, "-chunk"))
548 elog(ERROR, "array_in: access pattern file required");
549 str = _AdvanceBy1word(str, &accessfile);
551 else if (!strcmp(word, "-noreorg"))
554 elog(ERROR, "array_in: chunk file required");
555 str = _AdvanceBy1word(str, &chunkfile);
559 elog(ERROR, "usage: <input file> -chunk DEFAULT/<access pattern file> -invert/-native [-noreorg <chunk file>]");
563 if (inputfile == NULL)
564 elog(ERROR, "array_in: missing file name");
565 lobjId = lo_creat(0);
566 *fd = lo_open(lobjId, INV_READ);
568 elog(ERROR, "Large object create failed");
570 *nbytes = strlen(retStr) + 2;
576 if ((afd = AllocateFile(accessfile, "r")) == NULL)
577 elog(ERROR, "unable to open access pattern file");
579 retStr = _ChunkArray(*fd, afd, ndim, dim, baseSize, nbytes,
589 _CopyArrayEls(char **values,
598 for (i = 0; i < nitems; i++)
602 inc = ArrayCastAndSet(values[i], typbyval, typlen, p);
610 /*-------------------------------------------------------------------------
612 * takes the internal representation of an array and returns a string
613 * containing the array in its external format.
614 *-------------------------------------------------------------------------
617 array_out(ArrayType *v, Oid element_type)
642 if (v == (ArrayType *) NULL)
643 return ((char *) NULL);
645 if (ARR_IS_LO(v) == true)
651 /* get a wide string to print to */
652 p = array_dims(v, &dummy_bool);
653 nbytes = strlen(ARR_DATA_PTR(v)) + VARHDRSZ + *(int *) p;
655 save_p = (char *) palloc(nbytes);
657 strcpy(save_p, p + sizeof(int));
658 strcat(save_p, ASSGN);
659 strcat(save_p, ARR_DATA_PTR(v));
664 system_cache_lookup(element_type, false, &typlen, &typbyval,
665 &typdelim, &typelem, &typoutput, &typalign);
666 fmgr_info(typoutput, &outputproc);
667 sprintf(delim, "%c", typdelim);
670 nitems = getNitems(ndim, dim);
674 char *emptyArray = palloc(3);
678 emptyArray[2] = '\0';
683 overall_length = 1; /* [TRH] don't forget to count \0 at end. */
684 values = (char **) palloc(nitems * sizeof(char *));
685 for (i = 0; i < nitems; i++)
692 values[i] = (*fmgr_faddr(&outputproc)) (*p, typelem);
695 values[i] = (*fmgr_faddr(&outputproc)) (*(int16 *) p, typelem);
699 values[i] = (*fmgr_faddr(&outputproc)) (*(int32 *) p, typelem);
706 values[i] = (*fmgr_faddr(&outputproc)) (p, typelem);
710 p += INTALIGN(*(int32 *) p);
713 * For the pair of double quotes
717 for (tmp=values[i];*tmp;tmp++) {
719 if (*tmp=='"') overall_length += 1;
725 * count total number of curly braces in output string
727 for (i = j = 0, k = 1; i < ndim; k *= dim[i++], j += k);
729 p = (char *) palloc(overall_length + 2 * j);
733 for (i = 0; i < ndim; indx[i++] = 0);
738 for (i = j; i < ndim - 1; i++)
742 * Surround anything that is not passed by value in double quotes.
743 * See above for more details.
749 for (tmp=values[k];*tmp;tmp++) {
750 if (*tmp=='"') p[l++]='\\';
757 strcat(p, values[k]);
760 for (i = ndim - 1; i >= 0; i--)
762 indx[i] = (indx[i] + 1) % dim[i];
778 /*-----------------------------------------------------------------------------
780 * returns the dimension of the array pointed to by "v"
781 *----------------------------------------------------------------------------
784 array_dims(ArrayType *v, bool *isNull)
793 if (v == (ArrayType *) NULL)
795 nbytes = ARR_NDIM(v) * 33;
798 * 33 since we assume 15 digits per number + ':' +'[]'
800 save_p = p = (char *) palloc(nbytes + VARHDRSZ);
801 MemSet(save_p, 0, nbytes + VARHDRSZ);
805 for (i = 0; i < ARR_NDIM(v); i++)
807 sprintf(p, "[%d:%d]", lb[i], dimv[i] + lb[i] - 1);
810 nbytes = strlen(save_p + VARHDRSZ) + VARHDRSZ;
811 memmove(save_p, &nbytes, VARHDRSZ);
815 /*---------------------------------------------------------------------------
817 * This routing takes an array pointer and an index array and returns
818 * a pointer to the referred element if element is passed by
819 * reference otherwise returns the value of the referred element.
820 *---------------------------------------------------------------------------
823 array_ref(ArrayType *array,
837 struct varlena *v = NULL;
840 if (array == (ArrayType *) NULL)
846 * fixed length arrays -- these are assumed to be 1-d
848 if (indx[0] * elmlen > arraylen)
849 elog(ERROR, "array_ref: array bound exceeded");
850 retval = (char *) array + indx[0] * elmlen;
851 return _ArrayCast(retval, reftype, elmlen);
853 dim = ARR_DIMS(array);
854 lb = ARR_LBOUND(array);
855 ndim = ARR_NDIM(array);
856 nbytes = (*(int32 *) array) - ARR_OVERHEAD(ndim);
858 if (!SanityCheckInput(ndim, n, dim, lb, indx))
861 offset = GetOffset(n, dim, lb, indx);
863 if (ARR_IS_LO(array))
868 /* We are assuming fixed element lengths here */
870 lo_name = (char *) ARR_DATA_PTR(array);
872 if ((fd = LOopen(lo_name, ARR_IS_INV(array) ? INV_READ : O_RDONLY)) < 0)
875 if (ARR_IS_CHUNKED(array))
876 v = _ReadChunkArray1El(indx, elmlen, fd, array, isNull);
879 if (lo_lseek(fd, offset, SEEK_SET) < 0)
882 v = (struct varlena *) LOread(fd, elmlen);
887 if (VARSIZE(v) - VARHDRSZ < elmlen)
890 retval = (char *) _ArrayCast((char *) VARDATA(v), reftype, elmlen);
893 char *tempdata = palloc(elmlen);
895 memmove(tempdata, retval, elmlen);
899 return (Datum) retval;
904 offset = offset * elmlen;
905 /* off the end of the array */
906 if (nbytes - offset < 1)
908 retval = ARR_DATA_PTR(array) + offset;
909 return _ArrayCast(retval, reftype, elmlen);
917 temp = ARR_DATA_PTR(array);
919 while (bytes > 0 && !done)
926 bytes -= INTALIGN(*(int32 *) temp);
927 temp += INTALIGN(*(int32 *) temp);
932 return (Datum) retval;
936 /*-----------------------------------------------------------------------------
938 * This routine takes an array and a range of indices (upperIndex and
939 * lowerIndx), creates a new array structure for the referred elements
940 * and returns a pointer to it.
941 *-----------------------------------------------------------------------------
944 array_clip(ArrayType *array,
962 if (array == (ArrayType *) NULL)
964 dim = ARR_DIMS(array);
965 lb = ARR_LBOUND(array);
966 ndim = ARR_NDIM(array);
967 nbytes = (*(int32 *) array) - ARR_OVERHEAD(ndim);
969 if (!SanityCheckInput(ndim, n, dim, lb, upperIndx))
972 if (!SanityCheckInput(ndim, n, dim, lb, lowerIndx))
975 for (i = 0; i < n; i++)
976 if (lowerIndx[i] > upperIndx[i])
977 elog(ERROR, "lowerIndex cannot be larger than upperIndx");
978 mda_get_range(n, span, lowerIndx, upperIndx);
980 if (ARR_IS_LO(array))
986 char *newname = NULL;
993 elog(ERROR, "array_clip: array of variable length objects not supported");
995 lo_name = (char *) ARR_DATA_PTR(array);
996 if ((fd = LOopen(lo_name, ARR_IS_INV(array) ? INV_READ : O_RDONLY)) < 0)
998 newname = _array_newLO(&newfd, Unix);
1000 bytes = strlen(newname) + 1 + ARR_OVERHEAD(n);
1001 newArr = (ArrayType *) palloc(bytes);
1002 memmove(newArr, array, sizeof(ArrayType));
1003 memmove(newArr, &bytes, sizeof(int));
1004 memmove(ARR_DIMS(newArr), span, n * sizeof(int));
1005 memmove(ARR_LBOUND(newArr), lowerIndx, n * sizeof(int));
1006 strcpy(ARR_DATA_PTR(newArr), newname);
1008 rsize = compute_size(lowerIndx, upperIndx, n, len);
1009 if (rsize < MAX_BUFF_SIZE)
1014 buff = palloc(rsize);
1017 if (ARR_IS_CHUNKED(array))
1019 _ReadChunkArray(lowerIndx, upperIndx, len, fd, &(buff[VARHDRSZ]),
1024 _ReadArray(lowerIndx, upperIndx, len, fd, (int) &(buff[VARHDRSZ]),
1028 memmove(buff, &rsize, VARHDRSZ);
1031 bytes = LOwrite(newfd, (struct varlena *) buff);
1037 if (ARR_IS_CHUNKED(array))
1039 _ReadChunkArray(lowerIndx, upperIndx, len, fd, (char *) newfd, array,
1044 _ReadArray(lowerIndx, upperIndx, len, fd, newfd, array, 1, isNull);
1057 return ((Datum) newArr);
1062 bytes = getNitems(n, span);
1063 bytes = bytes * len + ARR_OVERHEAD(n);
1067 bytes = _ArrayClipCount(lowerIndx, upperIndx, array);
1068 bytes += ARR_OVERHEAD(n);
1070 newArr = (ArrayType *) palloc(bytes);
1071 memmove(newArr, array, sizeof(ArrayType));
1072 memmove(newArr, &bytes, sizeof(int));
1073 memmove(ARR_DIMS(newArr), span, n * sizeof(int));
1074 memmove(ARR_LBOUND(newArr), lowerIndx, n * sizeof(int));
1075 _ArrayRange(lowerIndx, upperIndx, len, ARR_DATA_PTR(newArr), array, 1);
1076 return (Datum) newArr;
1079 /*-----------------------------------------------------------------------------
1081 * This routine sets the value of an array location (specified by an index array)
1082 * to a new value specified by "dataPtr".
1084 * returns a pointer to the modified array.
1085 *-----------------------------------------------------------------------------
1088 array_set(ArrayType *array,
1104 if (array == (ArrayType *) NULL)
1110 * fixed length arrays -- these are assumed to be 1-d
1112 if (indx[0] * elmlen > arraylen)
1113 elog(ERROR, "array_ref: array bound exceeded");
1114 pos = (char *) array + indx[0] * elmlen;
1115 ArrayCastAndSet(dataPtr, (bool) reftype, elmlen, pos);
1116 return ((char *) array);
1118 dim = ARR_DIMS(array);
1119 lb = ARR_LBOUND(array);
1120 ndim = ARR_NDIM(array);
1121 nbytes = (*(int32 *) array) - ARR_OVERHEAD(ndim);
1123 if (!SanityCheckInput(ndim, n, dim, lb, indx))
1125 elog(ERROR, "array_set: array bound exceeded");
1126 return ((char *) array);
1128 offset = GetOffset(n, dim, lb, indx);
1130 if (ARR_IS_LO(array))
1135 /* We are assuming fixed element lengths here */
1140 lo_name = ARR_DATA_PTR(array);
1141 if ((fd = LOopen(lo_name, ARR_IS_INV(array) ? INV_WRITE : O_WRONLY)) < 0)
1142 return ((char *) array);
1144 if (lo_lseek(fd, offset, SEEK_SET) < 0)
1145 return ((char *) array);
1146 v = (struct varlena *) palloc(elmlen + VARHDRSZ);
1147 VARSIZE(v) = elmlen + VARHDRSZ;
1148 ArrayCastAndSet(dataPtr, (bool) reftype, elmlen, VARDATA(v));
1154 * if (n < VARSIZE(v) - VARHDRSZ) RETURN_NULL;
1158 return ((char *) array);
1162 offset = offset * elmlen;
1163 /* off the end of the array */
1164 if (nbytes - offset < 1)
1165 return ((char *) array);
1166 pos = ARR_DATA_PTR(array) + offset;
1170 ArrayType *newarray;
1180 elt_ptr = array_seek(ARR_DATA_PTR(array), -1, offset);
1181 oldlen = INTALIGN(*(int32 *) elt_ptr);
1182 newlen = INTALIGN(*(int32 *) dataPtr);
1184 if (oldlen == newlen)
1186 /* new element with same size, overwrite old data */
1187 ArrayCastAndSet(dataPtr, (bool) reftype, elmlen, elt_ptr);
1188 return ((char *) array);
1191 /* new element with different size, reallocate the array */
1192 oldsize = array->size;
1193 lth0 = ARR_OVERHEAD(n);
1194 lth1 = (int) (elt_ptr - ARR_DATA_PTR(array));
1195 lth2 = (int) (oldsize - lth0 - lth1 - oldlen);
1196 newsize = lth0 + lth1 + newlen + lth2;
1198 newarray = (ArrayType *) palloc(newsize);
1199 memmove((char *) newarray, (char *) array, lth0 + lth1);
1200 newarray->size = newsize;
1201 newlen = ArrayCastAndSet(dataPtr, (bool) reftype, elmlen,
1202 (char *) newarray + lth0 + lth1);
1203 memmove((char *) newarray + lth0 + lth1 + newlen,
1204 (char *) array + lth0 + lth1 + oldlen, lth2);
1206 /* ??? who should free this storage ??? */
1207 return ((char *) newarray);
1209 ArrayCastAndSet(dataPtr, (bool) reftype, elmlen, pos);
1210 return ((char *) array);
1213 /*----------------------------------------------------------------------------
1215 * This routine sets the value of a range of array locations (specified
1216 * by upper and lower index values ) to new values passed as
1219 * returns a pointer to the modified array.
1220 *----------------------------------------------------------------------------
1223 array_assgn(ArrayType *array,
1237 if (array == (ArrayType *) NULL)
1240 elog(ERROR, "array_assgn:updates on arrays of variable length elements not allowed");
1242 dim = ARR_DIMS(array);
1243 lb = ARR_LBOUND(array);
1244 ndim = ARR_NDIM(array);
1246 if (!SanityCheckInput(ndim, n, dim, lb, upperIndx) ||
1247 !SanityCheckInput(ndim, n, dim, lb, lowerIndx))
1249 return ((char *) array);
1252 for (i = 0; i < n; i++)
1253 if (lowerIndx[i] > upperIndx[i])
1254 elog(ERROR, "lowerIndex larger than upperIndx");
1256 if (ARR_IS_LO(array))
1264 lo_name = (char *) ARR_DATA_PTR(array);
1265 if ((fd = LOopen(lo_name, ARR_IS_INV(array) ? INV_WRITE : O_WRONLY)) < 0)
1266 return ((char *) array);
1268 if (ARR_IS_LO(newArr))
1271 lo_name = (char *) ARR_DATA_PTR(newArr);
1272 if ((newfd = LOopen(lo_name, ARR_IS_INV(newArr) ? INV_READ : O_RDONLY)) < 0)
1273 return ((char *) array);
1275 _LOArrayRange(lowerIndx, upperIndx, len, fd, newfd, array, 1, isNull);
1280 _LOArrayRange(lowerIndx, upperIndx, len, fd, (int) ARR_DATA_PTR(newArr),
1284 return ((char *) array);
1286 _ArrayRange(lowerIndx, upperIndx, len, ARR_DATA_PTR(newArr), array, 0);
1287 return (char *) array;
1290 /*-----------------------------------------------------------------------------
1292 * compares two arrays for equality
1294 * returns 1 if the arrays are equal, 0 otherwise.
1295 *-----------------------------------------------------------------------------
1298 array_eq(ArrayType *array1, ArrayType *array2)
1300 if ((array1 == NULL) || (array2 == NULL))
1302 if (*(int *) array1 != *(int *) array2)
1304 if (memcmp(array1, array2, *(int *) array1))
1309 /***************************************************************************/
1310 /******************| Support Routines |*****************/
1311 /***************************************************************************/
1313 system_cache_lookup(Oid element_type,
1322 HeapTuple typeTuple;
1323 TypeTupleForm typeStruct;
1325 typeTuple = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(element_type),
1328 if (!HeapTupleIsValid(typeTuple))
1330 elog(ERROR, "array_out: Cache lookup failed for type %d\n",
1334 typeStruct = (TypeTupleForm) GETSTRUCT(typeTuple);
1335 *typlen = typeStruct->typlen;
1336 *typbyval = typeStruct->typbyval;
1337 *typdelim = typeStruct->typdelim;
1338 *typelem = typeStruct->typelem;
1339 *typalign = typeStruct->typalign;
1342 *proc = typeStruct->typinput;
1346 *proc = typeStruct->typoutput;
1351 _ArrayCast(char *value, bool byval, int len)
1358 return ((Datum) *value);
1360 return ((Datum) *(int16 *) value);
1363 return ((Datum) *(int32 *) value);
1365 elog(ERROR, "array_ref: byval and elt len > 4!");
1371 return (Datum) value;
1378 ArrayCastAndSet(char *src,
1392 *dest = DatumGetChar(src);
1395 *(int16 *) dest = DatumGetInt16(src);
1398 *(int32 *) dest = (int32) src;
1404 memmove(dest, src, typlen);
1410 memmove(dest, src, *(int32 *) src);
1411 inc = (INTALIGN(*(int32 *) src));
1418 _AdvanceBy1word(char *str, char **word)
1426 while (isspace(*str))
1429 if ((space = (char *) strchr(str, ' ')) != (char *) NULL)
1442 SanityCheckInput(int ndim, int n, int dim[], int lb[], int indx[])
1446 /* Do Sanity check on input */
1449 for (i = 0; i < ndim; i++)
1450 if ((lb[i] > indx[i]) || (indx[i] >= (dim[i] + lb[i])))
1456 _ArrayRange(int st[],
1476 n = ARR_NDIM(array);
1477 dim = ARR_DIMS(array);
1478 lb = ARR_LBOUND(array);
1479 srcPtr = ARR_DATA_PTR(array);
1480 for (i = 0; i < n; st[i] -= lb[i], endp[i] -= lb[i], i++);
1481 mda_get_prod(n, dim, prod);
1482 st_pos = tuple2linear(n, st, prod);
1483 srcPtr = array_seek(srcPtr, bsize, st_pos);
1484 mda_get_range(n, span, st, endp);
1485 mda_get_offset_values(n, dist, prod, span);
1486 for (i = 0; i < n; indx[i++] = 0);
1491 srcPtr = array_seek(srcPtr, bsize, dist[j]);
1493 inc = array_read(destPtr, bsize, 1, srcPtr);
1495 inc = array_read(srcPtr, bsize, 1, destPtr);
1498 } while ((j = next_tuple(i + 1, indx, span)) != -1);
1502 _ArrayClipCount(int stI[], int endpI[], ArrayType *array)
1520 n = ARR_NDIM(array);
1521 dim = ARR_DIMS(array);
1522 lb = ARR_LBOUND(array);
1523 ptr = ARR_DATA_PTR(array);
1524 for (i = 0; i < n; st[i] = stI[i] - lb[i], endp[i] = endpI[i] - lb[i], i++);
1525 mda_get_prod(n, dim, prod);
1526 st_pos = tuple2linear(n, st, prod);
1527 ptr = array_seek(ptr, -1, st_pos);
1528 mda_get_range(n, span, st, endp);
1529 mda_get_offset_values(n, dist, prod, span);
1530 for (i = 0; i < n; indx[i++] = 0);
1534 ptr = array_seek(ptr, -1, dist[j]);
1535 inc = INTALIGN(*(int32 *) ptr);
1538 } while ((j = next_tuple(i + 1, indx, span)) != -1);
1543 array_seek(char *ptr, int eltsize, int nitems)
1548 return (ptr + eltsize * nitems);
1549 for (i = 0; i < nitems; i++)
1550 ptr += INTALIGN(*(int32 *) ptr);
1555 array_read(char *destptr, int eltsize, int nitems, char *srcptr)
1563 memmove(destptr, srcptr, eltsize * nitems);
1564 return (eltsize * nitems);
1566 for (i = inc = 0; i < nitems; i++)
1568 tmp = (INTALIGN(*(int32 *) srcptr));
1569 memmove(destptr, srcptr, tmp);
1578 _LOArrayRange(int st[],
1601 n = ARR_NDIM(array);
1602 dim = ARR_DIMS(array);
1603 lb = ARR_LBOUND(array);
1604 for (i = 0; i < n; st[i] -= lb[i], endp[i] -= lb[i], i++);
1606 mda_get_prod(n, dim, prod);
1607 st_pos = tuple2linear(n, st, prod);
1608 offset = st_pos * bsize;
1609 if (lo_lseek(srcfd, offset, SEEK_SET) < 0)
1611 mda_get_range(n, span, st, endp);
1612 mda_get_offset_values(n, dist, prod, span);
1613 for (i = 0; i < n; indx[i++] = 0);
1614 for (i = n - 1, inc = bsize; i >= 0; inc *= span[i--])
1620 offset += (dist[j] * bsize);
1621 if (lo_lseek(srcfd, offset, SEEK_SET) < 0)
1623 tmp = _LOtransfer((char **) &srcfd, inc, 1, (char **) &destfd, isSrcLO, 1);
1627 } while ((j = next_tuple(i + 1, indx, span)) != -1);
1632 _ReadArray(int st[],
1655 n = ARR_NDIM(array);
1656 dim = ARR_DIMS(array);
1657 lb = ARR_LBOUND(array);
1658 for (i = 0; i < n; st[i] -= lb[i], endp[i] -= lb[i], i++);
1660 mda_get_prod(n, dim, prod);
1661 st_pos = tuple2linear(n, st, prod);
1662 offset = st_pos * bsize;
1663 if (lo_lseek(srcfd, offset, SEEK_SET) < 0)
1665 mda_get_range(n, span, st, endp);
1666 mda_get_offset_values(n, dist, prod, span);
1667 for (i = 0; i < n; indx[i++] = 0);
1668 for (i = n - 1, inc = bsize; i >= 0; inc *= span[i--])
1674 offset += (dist[j] * bsize);
1675 if (lo_lseek(srcfd, offset, SEEK_SET) < 0)
1677 tmp = _LOtransfer((char **) &destfd, inc, 1, (char **) &srcfd, 1, isDestLO);
1681 } while ((j = next_tuple(i + 1, indx, span)) != -1);
1686 _LOtransfer(char **destfd,
1693 #define MAX_READ (512 * 1024)
1694 #define min(a, b) (a < b ? a : b)
1695 struct varlena *v = NULL;
1700 inc = nitems * size;
1701 if (isSrcLO && isDestLO && inc > 0)
1702 for (tmp = 0, resid = inc;
1703 resid > 0 && (inc = min(resid, MAX_READ)) > 0; resid -= inc)
1706 v = (struct varlena *) LOread((int) *srcfd, inc);
1707 if (VARSIZE(v) - VARHDRSZ < inc)
1712 tmp += LOwrite((int) *destfd, v);
1717 else if (!isSrcLO && isDestLO)
1719 tmp = lo_write((int) *destfd, *srcfd, inc);
1720 *srcfd = *srcfd + tmp;
1722 else if (isSrcLO && !isDestLO)
1724 tmp = lo_read((int) *srcfd, *destfd, inc);
1725 *destfd = *destfd + tmp;
1729 memmove(*destfd, *srcfd, inc);
1739 _array_newLO(int *fd, int flag)
1742 char saveName[NAME_LEN];
1744 p = (char *) palloc(NAME_LEN);
1745 sprintf(p, "/Arry.%d", newoid());
1746 strcpy(saveName, p);
1748 if ((*fd = LOcreat(saveName, 0600, flag)) < 0)
1749 elog(ERROR, "Large object create failed");