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.40 1999/05/03 23:48:26 tgl Exp $
12 *-------------------------------------------------------------------------
22 #include "catalog/catalog.h"
23 #include "catalog/pg_type.h"
25 #include "utils/syscache.h"
26 #include "utils/memutils.h"
27 #include "storage/fd.h"
29 #include "utils/array.h"
30 #include "utils/elog.h"
32 #include "libpq/libpq-fs.h"
33 #include "libpq/be-fsstubs.h"
37 /* An array has the following internal structure:
38 * <nbytes> - total number of bytes
39 * <ndim> - number of dimensions of the array
40 * <flags> - bit mask of flags
41 * <dim> - size of each array axis
42 * <dim_lower> - lower boundary of each dimension
43 * <actual data> - whatever is the stored data
46 /*-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-*/
47 static int _ArrayCount(char *str, int *dim, int typdelim);
48 static char *_ReadArrayStr(char *arrayStr, int nitems, int ndim, int *dim,
49 FmgrInfo *inputproc, Oid typelem, int32 typmod,
50 char typdelim, int typlen, bool typbyval,
51 char typalign, int *nbytes);
54 static char *_ReadLOArray(char *str, int *nbytes, int *fd, bool *chunkFlag,
55 int ndim, int *dim, int baseSize);
58 static void _CopyArrayEls(char **values, char *p, int nitems, int typlen,
59 char typalign, bool typbyval);
60 static void system_cache_lookup(Oid element_type, bool input, int *typlen,
61 bool *typbyval, char *typdelim, Oid *typelem, Oid *proc,
63 static Datum _ArrayCast(char *value, bool byval, int len);
66 static char *_AdvanceBy1word(char *str, char **word);
69 static void _ArrayRange(int *st, int *endp, int bsize, char *destPtr,
70 ArrayType *array, int from);
71 static int _ArrayClipCount(int *stI, int *endpI, ArrayType *array);
72 static void _LOArrayRange(int *st, int *endp, int bsize, int srcfd,
73 int destfd, ArrayType *array, int isSrcLO, bool *isNull);
74 static void _ReadArray(int *st, int *endp, int bsize, int srcfd, int destfd,
75 ArrayType *array, int isDestLO, bool *isNull);
76 static int ArrayCastAndSet(char *src, bool typbyval, int typlen, char *dest);
77 static int SanityCheckInput(int ndim, int n, int *dim, int *lb, int *indx);
78 static int array_read(char *destptr, int eltsize, int nitems, char *srcptr);
79 static char *array_seek(char *ptr, int eltsize, int nitems);
81 /*---------------------------------------------------------------------
83 * converts an array from the external format in "string" to
86 * the internal representation of the input array
87 *--------------------------------------------------------------------
90 array_in(char *string, /* input array in external form */
91 Oid element_type, /* type OID of an array element */
109 ArrayType *retval = NULL;
115 system_cache_lookup(element_type, true, &typlen, &typbyval, &typdelim,
116 &typelem, &typinput, &typalign);
118 fmgr_info(typinput, &inputproc);
120 string_save = (char *) palloc(strlen(string) + 3);
121 strcpy(string_save, string);
123 /* --- read array dimensions ---------- */
126 for (ndim = 0; !done;)
133 if ((r = (char *) strchr(p, ':')) == (char *) NULL)
138 lBound[ndim] = atoi(p);
141 for (q = p; isdigit(*q); q++);
143 elog(ERROR, "array_in: missing ']' in array declaration");
146 if ((dim[ndim] < 0) || (lBound[ndim] < 0))
147 elog(ERROR, "array_in: array dimensions need to be positive");
148 dim[ndim] = dim[ndim] - lBound[ndim] + 1;
150 elog(ERROR, "array_in: upper_bound cannot be < lower_bound");
162 ndim = _ArrayCount(p, dim, typdelim);
163 for (i = 0; i < ndim; lBound[i++] = 1);
166 elog(ERROR, "array_in: Need to specify dimension");
172 if (strncmp(p, ASSGN, strlen(ASSGN)))
173 elog(ERROR, "array_in: missing assignment operator");
180 printf("array_in- ndim %d (", ndim);
181 for (i = 0; i < ndim; i++)
183 printf(" %d", dim[i]);
185 printf(") for %s\n", string);
188 nitems = getNitems(ndim, dim);
191 char *emptyArray = palloc(sizeof(ArrayType));
193 MemSet(emptyArray, 0, sizeof(ArrayType));
194 *(int32 *) emptyArray = sizeof(ArrayType);
200 /* array not a large object */
201 dataPtr = (char *) _ReadArrayStr(p, nitems, ndim, dim, &inputproc, typelem,
202 typmod, typdelim, typlen, typbyval, typalign,
204 nbytes += ARR_OVERHEAD(ndim);
205 retval = (ArrayType *) palloc(nbytes);
206 MemSet(retval, 0, nbytes);
207 memmove(retval, (char *) &nbytes, sizeof(int));
208 memmove((char *) ARR_NDIM_PTR(retval), (char *) &ndim, sizeof(int));
209 SET_LO_FLAG(false, retval);
210 memmove((char *) ARR_DIMS(retval), (char *) dim, ndim * sizeof(int));
211 memmove((char *) ARR_LBOUND(retval), (char *) lBound,
215 * dataPtr is an array of arbitraystuff even though its type is
216 * char* cast to char** to pass to _CopyArrayEls for now - jolly
218 _CopyArrayEls((char **) dataPtr,
219 ARR_DATA_PTR(retval), nitems,
220 typlen, typalign, typbyval);
227 bool chunked = false;
229 dataPtr = _ReadLOArray(p, &bytes, &dummy, &chunked, ndim,
231 nbytes = bytes + ARR_OVERHEAD(ndim);
232 retval = (ArrayType *) palloc(nbytes);
233 MemSet(retval, 0, nbytes);
234 memmove(retval, (char *) &nbytes, sizeof(int));
235 memmove((char *) ARR_NDIM_PTR(retval), (char *) &ndim, sizeof(int));
236 SET_LO_FLAG(true, retval);
237 SET_CHUNK_FLAG(chunked, retval);
238 memmove((char *) ARR_DIMS(retval), (char *) dim, ndim * sizeof(int));
239 memmove((char *) ARR_LBOUND(retval), (char *) lBound, ndim * sizeof(int));
240 memmove(ARR_DATA_PTR(retval), dataPtr, bytes);
242 elog(ERROR, "large object arrays not supported");
245 return (char *) retval;
248 /*-----------------------------------------------------------------------------
250 * Counts the number of dimensions and the *dim array for an array string.
251 * The syntax for array input is C-like nested curly braces
252 *-----------------------------------------------------------------------------
255 _ArrayCount(char *str, int *dim, int typdelim)
261 bool scanning_string = false;
262 bool eoArray = false;
265 for (i = 0; i < MAXDIM; ++i)
266 temp[i] = dim[i] = 0;
268 if (strncmp(str, "{}", 2) == 0)
272 while (eoArray != true)
281 /* skip escaped characters (\ and ") inside strings */
282 if (scanning_string && *(q + 1))
288 * Signal a premature end of the string. DZ -
291 elog(ERROR, "malformed array constant: %s", str);
294 scanning_string = !scanning_string;
297 if (!scanning_string)
299 temp[nest_level] = 0;
304 if (!scanning_string)
310 temp[nest_level - 1]++;
312 eoArray = done = true;
318 if (*q == typdelim && !scanning_string)
331 for (i = 0; i < ndim; ++i)
337 /*---------------------------------------------------------------------------
339 * parses the array string pointed by "arrayStr" and converts it in the
340 * internal format. The external format expected is like C array
341 * declaration. Unspecified elements are initialized to zero for fixed length
342 * base types and to empty varlena structures for variable length base
345 * returns the internal representation of the array elements
346 * nbytes is set to the size of the array in its internal representation.
347 *---------------------------------------------------------------------------
350 _ReadArrayStr(char *arrayStr,
354 FmgrInfo *inputproc, /* function used for the
370 bool scanning_string = false;
373 bool eoArray = false;
375 mda_get_prod(ndim, dim, prod);
376 for (i = 0; i < ndim; indx[i++] = 0);
377 /* read array enclosed within {} */
378 values = (char **) palloc(nitems * sizeof(char *));
379 MemSet(values, 0, nitems * sizeof(char *));
392 /* Crunch the string on top of the backslash. */
393 for (r = q; *r != '\0'; r++)
397 if (!scanning_string)
401 p++; /* get p past first doublequote */
405 scanning_string = !scanning_string;
408 if (!scanning_string)
412 if (nest_level > ndim)
413 elog(ERROR, "array_in: illformed array constant");
414 indx[nest_level - 1] = 0;
419 if (!scanning_string)
422 i = tuple2linear(ndim, indx, prod);
425 eoArray = done = true;
429 indx[nest_level - 1]++;
434 if (*q == typdelim && !scanning_string)
437 i = tuple2linear(ndim, indx, prod);
448 elog(ERROR, "array_in: illformed array constant");
449 values[i] = (*fmgr_faddr(inputproc)) (p, typelem, typmod);
454 * if not at the end of the array skip white space
464 *nbytes = nitems * typlen;
466 for (i = 0; i < nitems; i++)
469 values[i] = palloc(typlen);
470 MemSet(values[i], 0, typlen);
475 for (i = 0, *nbytes = 0; i < nitems; i++)
480 *nbytes += DOUBLEALIGN(*(int32 *) values[i]);
482 *nbytes += INTALIGN(*(int32 *) values[i]);
486 *nbytes += sizeof(int32);
487 values[i] = palloc(sizeof(int32));
488 *(int32 *) values[i] = sizeof(int32);
492 return (char *) values;
496 /*----------------------------------------------------------------------------
497 * Read data about an array to be stored as a large object
498 *----------------------------------------------------------------------------
502 _ReadLOArray(char *str,
517 str = _AdvanceBy1word(str, &inputfile);
523 str = _AdvanceBy1word(str, &word);
525 if (!strcmp(word, "-chunk"))
528 elog(ERROR, "array_in: access pattern file required");
529 str = _AdvanceBy1word(str, &accessfile);
531 else if (!strcmp(word, "-noreorg"))
534 elog(ERROR, "array_in: chunk file required");
535 str = _AdvanceBy1word(str, &chunkfile);
538 elog(ERROR, "usage: <input file> -chunk DEFAULT/<access pattern file> -invert/-native [-noreorg <chunk file>]");
541 if (inputfile == NULL)
542 elog(ERROR, "array_in: missing file name");
543 lobjId = lo_creat(0);
544 *fd = lo_open(lobjId, INV_READ);
546 elog(ERROR, "Large object create failed");
548 *nbytes = strlen(retStr) + 2;
555 if ((afd = AllocateFile(accessfile, "r")) == NULL)
557 if ((afd = AllocateFile(accessfile, "r")) == NULL)
559 elog(ERROR, "unable to open access pattern file");
561 retStr = _ChunkArray(*fd, afd, ndim, dim, baseSize, nbytes,
571 _CopyArrayEls(char **values,
580 for (i = 0; i < nitems; i++)
584 inc = ArrayCastAndSet(values[i], typbyval, typlen, p);
592 /*-------------------------------------------------------------------------
594 * takes the internal representation of an array and returns a string
595 * containing the array in its external format.
596 *-------------------------------------------------------------------------
599 array_out(ArrayType *v, Oid element_type)
627 if (v == (ArrayType *) NULL)
628 return (char *) NULL;
630 if (ARR_IS_LO(v) == true)
636 /* get a wide string to print to */
637 p = array_dims(v, &dummy_bool);
638 nbytes = strlen(ARR_DATA_PTR(v)) + VARHDRSZ + *(int *) p;
640 save_p = (char *) palloc(nbytes);
642 strcpy(save_p, p + sizeof(int));
643 strcat(save_p, ASSGN);
644 strcat(save_p, ARR_DATA_PTR(v));
649 system_cache_lookup(element_type, false, &typlen, &typbyval,
650 &typdelim, &typelem, &typoutput, &typalign);
651 fmgr_info(typoutput, &outputproc);
652 sprintf(delim, "%c", typdelim);
655 nitems = getNitems(ndim, dim);
659 char *emptyArray = palloc(3);
663 emptyArray[2] = '\0';
668 overall_length = 1; /* [TRH] don't forget to count \0 at end. */
669 values = (char **) palloc(nitems * sizeof(char *));
670 for (i = 0; i < nitems; i++)
677 values[i] = (*fmgr_faddr(&outputproc)) (*p, typelem);
680 values[i] = (*fmgr_faddr(&outputproc)) (*(int16 *) p, typelem);
684 values[i] = (*fmgr_faddr(&outputproc)) (*(int32 *) p, typelem);
691 values[i] = (*fmgr_faddr(&outputproc)) (p, typelem);
695 p += INTALIGN(*(int32 *) p);
698 * For the pair of double quotes
702 for (tmp = values[i]; *tmp; tmp++)
714 * count total number of curly braces in output string
716 for (i = j = 0, k = 1; i < ndim; k *= dim[i++], j += k);
718 p = (char *) palloc(overall_length + 2 * j);
722 for (i = 0; i < ndim; indx[i++] = 0);
727 for (i = j; i < ndim - 1; i++)
731 * Surround anything that is not passed by value in double quotes.
732 * See above for more details.
739 for (tmp = values[k]; *tmp; tmp++)
747 strcat(p, values[k]);
752 strcat(p, values[k]);
755 for (i = ndim - 1; i >= 0; i--)
757 indx[i] = (indx[i] + 1) % dim[i];
773 /*-----------------------------------------------------------------------------
775 * returns the dimension of the array pointed to by "v"
776 *----------------------------------------------------------------------------
779 array_dims(ArrayType *v, bool *isNull)
788 if (v == (ArrayType *) NULL)
790 nbytes = ARR_NDIM(v) * 33;
793 * 33 since we assume 15 digits per number + ':' +'[]'
795 save_p = p = (char *) palloc(nbytes + VARHDRSZ);
796 MemSet(save_p, 0, nbytes + VARHDRSZ);
800 for (i = 0; i < ARR_NDIM(v); i++)
802 sprintf(p, "[%d:%d]", lb[i], dimv[i] + lb[i] - 1);
805 nbytes = strlen(save_p + VARHDRSZ) + VARHDRSZ;
806 memmove(save_p, &nbytes, VARHDRSZ);
810 /*---------------------------------------------------------------------------
812 * This routing takes an array pointer and an index array and returns
813 * a pointer to the referred element if element is passed by
814 * reference otherwise returns the value of the referred element.
815 *---------------------------------------------------------------------------
818 array_ref(ArrayType *array,
832 struct varlena *v = NULL;
835 if (array == (ArrayType *) NULL)
841 * fixed length arrays -- these are assumed to be 1-d
843 if (indx[0] * elmlen > arraylen)
844 elog(ERROR, "array_ref: array bound exceeded");
845 retval = (char *) array + indx[0] * elmlen;
846 return _ArrayCast(retval, reftype, elmlen);
848 dim = ARR_DIMS(array);
849 lb = ARR_LBOUND(array);
850 ndim = ARR_NDIM(array);
851 nbytes = (*(int32 *) array) - ARR_OVERHEAD(ndim);
853 if (!SanityCheckInput(ndim, n, dim, lb, indx))
856 offset = GetOffset(n, dim, lb, indx);
858 if (ARR_IS_LO(array))
863 /* We are assuming fixed element lengths here */
865 lo_name = (char *) ARR_DATA_PTR(array);
867 if ((fd = LOopen(lo_name, ARR_IS_INV(array) ? INV_READ : O_RDONLY)) < 0)
870 if (ARR_IS_CHUNKED(array))
871 v = _ReadChunkArray1El(indx, elmlen, fd, array, isNull);
874 if (lo_lseek(fd, offset, SEEK_SET) < 0)
877 v = (struct varlena *) LOread(fd, elmlen);
882 if (VARSIZE(v) - VARHDRSZ < elmlen)
885 retval = (char *) _ArrayCast((char *) VARDATA(v), reftype, elmlen);
888 char *tempdata = palloc(elmlen);
890 memmove(tempdata, retval, elmlen);
894 return (Datum) retval;
899 offset = offset * elmlen;
900 /* off the end of the array */
901 if (nbytes - offset < 1)
903 retval = ARR_DATA_PTR(array) + offset;
904 return _ArrayCast(retval, reftype, elmlen);
912 temp = ARR_DATA_PTR(array);
914 while (bytes > 0 && !done)
921 bytes -= INTALIGN(*(int32 *) temp);
922 temp += INTALIGN(*(int32 *) temp);
927 return (Datum) retval;
931 /*-----------------------------------------------------------------------------
933 * This routine takes an array and a range of indices (upperIndex and
934 * lowerIndx), creates a new array structure for the referred elements
935 * and returns a pointer to it.
936 *-----------------------------------------------------------------------------
939 array_clip(ArrayType *array,
957 if (array == (ArrayType *) NULL)
959 dim = ARR_DIMS(array);
960 lb = ARR_LBOUND(array);
961 ndim = ARR_NDIM(array);
962 nbytes = (*(int32 *) array) - ARR_OVERHEAD(ndim);
964 if (!SanityCheckInput(ndim, n, dim, lb, upperIndx))
967 if (!SanityCheckInput(ndim, n, dim, lb, lowerIndx))
970 for (i = 0; i < n; i++)
971 if (lowerIndx[i] > upperIndx[i])
972 elog(ERROR, "lowerIndex cannot be larger than upperIndx");
973 mda_get_range(n, span, lowerIndx, upperIndx);
975 if (ARR_IS_LO(array))
981 char *newname = NULL;
988 elog(ERROR, "array_clip: array of variable length objects not supported");
990 lo_name = (char *) ARR_DATA_PTR(array);
991 if ((fd = LOopen(lo_name, ARR_IS_INV(array) ? INV_READ : O_RDONLY)) < 0)
993 newname = _array_newLO(&newfd, Unix);
995 bytes = strlen(newname) + 1 + ARR_OVERHEAD(n);
996 newArr = (ArrayType *) palloc(bytes);
997 memmove(newArr, array, sizeof(ArrayType));
998 memmove(newArr, &bytes, sizeof(int));
999 memmove(ARR_DIMS(newArr), span, n * sizeof(int));
1000 memmove(ARR_LBOUND(newArr), lowerIndx, n * sizeof(int));
1001 strcpy(ARR_DATA_PTR(newArr), newname);
1003 rsize = compute_size(lowerIndx, upperIndx, n, len);
1004 if (rsize < MAX_BUFF_SIZE)
1009 buff = palloc(rsize);
1012 if (ARR_IS_CHUNKED(array))
1014 _ReadChunkArray(lowerIndx, upperIndx, len, fd, &(buff[VARHDRSZ]),
1019 _ReadArray(lowerIndx, upperIndx, len, fd, (int) &(buff[VARHDRSZ]),
1023 memmove(buff, &rsize, VARHDRSZ);
1026 bytes = LOwrite(newfd, (struct varlena *) buff);
1032 if (ARR_IS_CHUNKED(array))
1034 _ReadChunkArray(lowerIndx, upperIndx, len, fd, (char *) newfd, array,
1038 _ReadArray(lowerIndx, upperIndx, len, fd, newfd, array, 1, isNull);
1050 return (Datum) newArr;
1055 bytes = getNitems(n, span);
1056 bytes = bytes * len + ARR_OVERHEAD(n);
1060 bytes = _ArrayClipCount(lowerIndx, upperIndx, array);
1061 bytes += ARR_OVERHEAD(n);
1063 newArr = (ArrayType *) palloc(bytes);
1064 memmove(newArr, array, sizeof(ArrayType));
1065 memmove(newArr, &bytes, sizeof(int));
1066 memmove(ARR_DIMS(newArr), span, n * sizeof(int));
1067 memmove(ARR_LBOUND(newArr), lowerIndx, n * sizeof(int));
1068 _ArrayRange(lowerIndx, upperIndx, len, ARR_DATA_PTR(newArr), array, 1);
1069 return (Datum) newArr;
1072 /*-----------------------------------------------------------------------------
1074 * This routine sets the value of an array location (specified by an index array)
1075 * to a new value specified by "dataPtr".
1077 * returns a pointer to the modified array.
1078 *-----------------------------------------------------------------------------
1081 array_set(ArrayType *array,
1097 if (array == (ArrayType *) NULL)
1103 * fixed length arrays -- these are assumed to be 1-d
1105 if (indx[0] * elmlen > arraylen)
1106 elog(ERROR, "array_ref: array bound exceeded");
1107 pos = (char *) array + indx[0] * elmlen;
1108 ArrayCastAndSet(dataPtr, (bool) reftype, elmlen, pos);
1109 return (char *) array;
1111 dim = ARR_DIMS(array);
1112 lb = ARR_LBOUND(array);
1113 ndim = ARR_NDIM(array);
1114 nbytes = (*(int32 *) array) - ARR_OVERHEAD(ndim);
1116 if (!SanityCheckInput(ndim, n, dim, lb, indx))
1118 elog(ERROR, "array_set: array bound exceeded");
1119 return (char *) array;
1121 offset = GetOffset(n, dim, lb, indx);
1123 if (ARR_IS_LO(array))
1128 /* We are assuming fixed element lengths here */
1133 lo_name = ARR_DATA_PTR(array);
1134 if ((fd = LOopen(lo_name, ARR_IS_INV(array) ? INV_WRITE : O_WRONLY)) < 0)
1135 return (char *) array;
1137 if (lo_lseek(fd, offset, SEEK_SET) < 0)
1138 return (char *) array;
1139 v = (struct varlena *) palloc(elmlen + VARHDRSZ);
1140 VARSIZE(v) = elmlen + VARHDRSZ;
1141 ArrayCastAndSet(dataPtr, (bool) reftype, elmlen, VARDATA(v));
1147 * if (n < VARSIZE(v) - VARHDRSZ) RETURN_NULL;
1151 return (char *) array;
1155 offset = offset * elmlen;
1156 /* off the end of the array */
1157 if (nbytes - offset < 1)
1158 return (char *) array;
1159 pos = ARR_DATA_PTR(array) + offset;
1163 ArrayType *newarray;
1173 elt_ptr = array_seek(ARR_DATA_PTR(array), -1, offset);
1174 oldlen = INTALIGN(*(int32 *) elt_ptr);
1175 newlen = INTALIGN(*(int32 *) dataPtr);
1177 if (oldlen == newlen)
1179 /* new element with same size, overwrite old data */
1180 ArrayCastAndSet(dataPtr, (bool) reftype, elmlen, elt_ptr);
1181 return (char *) array;
1184 /* new element with different size, reallocate the array */
1185 oldsize = array->size;
1186 lth0 = ARR_OVERHEAD(n);
1187 lth1 = (int) (elt_ptr - ARR_DATA_PTR(array));
1188 lth2 = (int) (oldsize - lth0 - lth1 - oldlen);
1189 newsize = lth0 + lth1 + newlen + lth2;
1191 newarray = (ArrayType *) palloc(newsize);
1192 memmove((char *) newarray, (char *) array, lth0 + lth1);
1193 newarray->size = newsize;
1194 newlen = ArrayCastAndSet(dataPtr, (bool) reftype, elmlen,
1195 (char *) newarray + lth0 + lth1);
1196 memmove((char *) newarray + lth0 + lth1 + newlen,
1197 (char *) array + lth0 + lth1 + oldlen, lth2);
1199 /* ??? who should free this storage ??? */
1200 return (char *) newarray;
1202 ArrayCastAndSet(dataPtr, (bool) reftype, elmlen, pos);
1203 return (char *) array;
1206 /*----------------------------------------------------------------------------
1208 * This routine sets the value of a range of array locations (specified
1209 * by upper and lower index values ) to new values passed as
1212 * returns a pointer to the modified array.
1213 *----------------------------------------------------------------------------
1216 array_assgn(ArrayType *array,
1230 if (array == (ArrayType *) NULL)
1233 elog(ERROR, "array_assgn:updates on arrays of variable length elements not allowed");
1235 dim = ARR_DIMS(array);
1236 lb = ARR_LBOUND(array);
1237 ndim = ARR_NDIM(array);
1239 if (!SanityCheckInput(ndim, n, dim, lb, upperIndx) ||
1240 !SanityCheckInput(ndim, n, dim, lb, lowerIndx))
1241 return (char *) array;
1243 for (i = 0; i < n; i++)
1244 if (lowerIndx[i] > upperIndx[i])
1245 elog(ERROR, "lowerIndex larger than upperIndx");
1247 if (ARR_IS_LO(array))
1255 lo_name = (char *) ARR_DATA_PTR(array);
1256 if ((fd = LOopen(lo_name, ARR_IS_INV(array) ? INV_WRITE : O_WRONLY)) < 0)
1257 return (char *) array;
1259 if (ARR_IS_LO(newArr))
1262 lo_name = (char *) ARR_DATA_PTR(newArr);
1263 if ((newfd = LOopen(lo_name, ARR_IS_INV(newArr) ? INV_READ : O_RDONLY)) < 0)
1264 return (char *) array;
1266 _LOArrayRange(lowerIndx, upperIndx, len, fd, newfd, array, 1, isNull);
1271 _LOArrayRange(lowerIndx, upperIndx, len, fd, (int) ARR_DATA_PTR(newArr),
1275 return (char *) array;
1277 _ArrayRange(lowerIndx, upperIndx, len, ARR_DATA_PTR(newArr), array, 0);
1278 return (char *) array;
1284 * Map an arbitrary function to an array and return a new array with
1285 * same dimensions and the source elements transformed by fn().
1288 array_map(ArrayType *v,
1316 /* Large objects not yet supported */
1317 if (ARR_IS_LO(v) == true) {
1318 elog(ERROR, "array_map: large objects not supported");
1322 if ((nargs < 0) || (nargs > 4)) {
1323 elog(ERROR, "array_map: invalid nargs: %d", nargs);
1326 /* Copy extra args to local variable */
1327 va_start(ap, nargs);
1328 for (i=0; i<nargs; i++) {
1329 args[i] = (void *) va_arg(ap, char *);
1333 /* Lookup source and result types. Unneeded variables are reused. */
1334 system_cache_lookup(type, false, &inp_typlen, &inp_typbyval,
1335 &typdelim, &typelem, &proc, &typalign);
1336 system_cache_lookup(retType, false, &typlen, &typbyval,
1337 &typdelim, &typelem, &proc, &typalign);
1339 /* Allocate temporary array for new values */
1342 nitems = getNitems(ndim, dim);
1343 values = (char **) palloc(nitems * sizeof(char *));
1344 MemSet(values, 0, nitems * sizeof(char *));
1346 /* Loop over source data */
1347 s = (char *) ARR_DATA_PTR(v);
1348 for (i=0; i<nitems; i++) {
1349 /* Get source element */
1351 switch (inp_typlen) {
1353 elt = (char *) ((int) (*(char *) s));
1356 elt = (char *) ((int) (*(int16 *) s));
1361 elt = (char *) (*(int32 *) s);
1367 if (inp_typlen > 0) {
1370 s += INTALIGN(*(int32 *) s);
1375 * Apply the given function to source elt and extra args.
1376 * nargs is the number of extra args taken by fn().
1380 p = (char *) (*fn) (elt);
1383 p = (char *) (*fn) (elt, args[0]);
1386 p = (char *) (*fn) (elt, args[0], args[1]);
1389 p = (char *) (*fn) (elt, args[0], args[1], args[2]);
1393 p = (char *) (*fn) (elt, args[0], args[1], args[2], args[3]);
1397 /* Update values and total result size */
1399 values[i] = (char *) p;
1403 len = ((typlen > 0) ? typlen : INTALIGN(*(int32 *) p));
1404 /* Needed because _CopyArrayEls tries to pfree items */
1406 p = (char *) palloc(len);
1407 memcpy(p, elt, len);
1409 values[i] = (char *) p;
1414 /* Allocate and initialize the result array */
1415 nbytes += ARR_OVERHEAD(ndim);
1416 result = (ArrayType *) palloc(nbytes);
1417 MemSet(result, 0, nbytes);
1419 memcpy((char *) result, (char *) &nbytes, sizeof(int));
1420 memcpy((char *) ARR_NDIM_PTR(result), (char *) &ndim, sizeof(int));
1421 memcpy((char *) ARR_DIMS(result), ARR_DIMS(v), 2 * ndim * sizeof(int));
1423 /* Copy new values into the result array. values is pfreed. */
1424 _CopyArrayEls((char **) values,
1425 ARR_DATA_PTR(result), nitems,
1426 typlen, typalign, typbyval);
1431 /*-----------------------------------------------------------------------------
1433 * compares two arrays for equality
1435 * returns 1 if the arrays are equal, 0 otherwise.
1436 *-----------------------------------------------------------------------------
1439 array_eq(ArrayType *array1, ArrayType *array2)
1441 if ((array1 == NULL) || (array2 == NULL))
1443 if (*(int *) array1 != *(int *) array2)
1445 if (memcmp(array1, array2, *(int *) array1))
1450 /***************************************************************************/
1451 /******************| Support Routines |*****************/
1452 /***************************************************************************/
1454 system_cache_lookup(Oid element_type,
1463 HeapTuple typeTuple;
1464 Form_pg_type typeStruct;
1466 typeTuple = SearchSysCacheTuple(TYPOID,
1467 ObjectIdGetDatum(element_type),
1470 if (!HeapTupleIsValid(typeTuple))
1472 elog(ERROR, "array_out: Cache lookup failed for type %d\n",
1476 typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
1477 *typlen = typeStruct->typlen;
1478 *typbyval = typeStruct->typbyval;
1479 *typdelim = typeStruct->typdelim;
1480 *typelem = typeStruct->typelem;
1481 *typalign = typeStruct->typalign;
1483 *proc = typeStruct->typinput;
1485 *proc = typeStruct->typoutput;
1489 _ArrayCast(char *value, bool byval, int len)
1496 return (Datum) *value;
1498 return (Datum) *(int16 *) value;
1501 return (Datum) *(int32 *) value;
1503 elog(ERROR, "array_ref: byval and elt len > 4!");
1508 return (Datum) value;
1514 ArrayCastAndSet(char *src,
1528 *dest = DatumGetChar(src);
1531 *(int16 *) dest = DatumGetInt16(src);
1534 *(int32 *) dest = (int32) src;
1539 memmove(dest, src, typlen);
1544 memmove(dest, src, *(int32 *) src);
1545 inc = (INTALIGN(*(int32 *) src));
1552 _AdvanceBy1word(char *str, char **word)
1560 while (isspace(*str))
1563 if ((space = (char *) strchr(str, ' ')) != (char *) NULL)
1576 SanityCheckInput(int ndim, int n, int *dim, int *lb, int *indx)
1580 /* Do Sanity check on input */
1583 for (i = 0; i < ndim; i++)
1584 if ((lb[i] > indx[i]) || (indx[i] >= (dim[i] + lb[i])))
1590 _ArrayRange(int *st,
1610 n = ARR_NDIM(array);
1611 dim = ARR_DIMS(array);
1612 lb = ARR_LBOUND(array);
1613 srcPtr = ARR_DATA_PTR(array);
1614 for (i = 0; i < n; st[i] -= lb[i], endp[i] -= lb[i], i++);
1615 mda_get_prod(n, dim, prod);
1616 st_pos = tuple2linear(n, st, prod);
1617 srcPtr = array_seek(srcPtr, bsize, st_pos);
1618 mda_get_range(n, span, st, endp);
1619 mda_get_offset_values(n, dist, prod, span);
1620 for (i = 0; i < n; indx[i++] = 0);
1625 srcPtr = array_seek(srcPtr, bsize, dist[j]);
1627 inc = array_read(destPtr, bsize, 1, srcPtr);
1629 inc = array_read(srcPtr, bsize, 1, destPtr);
1632 } while ((j = next_tuple(i + 1, indx, span)) != -1);
1636 _ArrayClipCount(int *stI, int *endpI, ArrayType *array)
1654 n = ARR_NDIM(array);
1655 dim = ARR_DIMS(array);
1656 lb = ARR_LBOUND(array);
1657 ptr = ARR_DATA_PTR(array);
1658 for (i = 0; i < n; st[i] = stI[i] - lb[i], endp[i] = endpI[i] - lb[i], i++);
1659 mda_get_prod(n, dim, prod);
1660 st_pos = tuple2linear(n, st, prod);
1661 ptr = array_seek(ptr, -1, st_pos);
1662 mda_get_range(n, span, st, endp);
1663 mda_get_offset_values(n, dist, prod, span);
1664 for (i = 0; i < n; indx[i++] = 0);
1668 ptr = array_seek(ptr, -1, dist[j]);
1669 inc = INTALIGN(*(int32 *) ptr);
1672 } while ((j = next_tuple(i + 1, indx, span)) != -1);
1677 array_seek(char *ptr, int eltsize, int nitems)
1682 return ptr + eltsize * nitems;
1683 for (i = 0; i < nitems; i++)
1684 ptr += INTALIGN(*(int32 *) ptr);
1689 array_read(char *destptr, int eltsize, int nitems, char *srcptr)
1697 memmove(destptr, srcptr, eltsize * nitems);
1698 return eltsize * nitems;
1700 for (i = inc = 0; i < nitems; i++)
1702 tmp = (INTALIGN(*(int32 *) srcptr));
1703 memmove(destptr, srcptr, tmp);
1712 _LOArrayRange(int *st,
1735 n = ARR_NDIM(array);
1736 dim = ARR_DIMS(array);
1737 lb = ARR_LBOUND(array);
1738 for (i = 0; i < n; st[i] -= lb[i], endp[i] -= lb[i], i++);
1740 mda_get_prod(n, dim, prod);
1741 st_pos = tuple2linear(n, st, prod);
1742 offset = st_pos * bsize;
1743 if (lo_lseek(srcfd, offset, SEEK_SET) < 0)
1745 mda_get_range(n, span, st, endp);
1746 mda_get_offset_values(n, dist, prod, span);
1747 for (i = 0; i < n; indx[i++] = 0);
1748 for (i = n - 1, inc = bsize; i >= 0; inc *= span[i--])
1754 offset += (dist[j] * bsize);
1755 if (lo_lseek(srcfd, offset, SEEK_SET) < 0)
1757 tmp = _LOtransfer((char **) &srcfd, inc, 1, (char **) &destfd, isSrcLO, 1);
1761 } while ((j = next_tuple(i + 1, indx, span)) != -1);
1789 n = ARR_NDIM(array);
1790 dim = ARR_DIMS(array);
1791 lb = ARR_LBOUND(array);
1792 for (i = 0; i < n; st[i] -= lb[i], endp[i] -= lb[i], i++);
1794 mda_get_prod(n, dim, prod);
1795 st_pos = tuple2linear(n, st, prod);
1796 offset = st_pos * bsize;
1797 if (lo_lseek(srcfd, offset, SEEK_SET) < 0)
1799 mda_get_range(n, span, st, endp);
1800 mda_get_offset_values(n, dist, prod, span);
1801 for (i = 0; i < n; indx[i++] = 0);
1802 for (i = n - 1, inc = bsize; i >= 0; inc *= span[i--])
1808 offset += (dist[j] * bsize);
1809 if (lo_lseek(srcfd, offset, SEEK_SET) < 0)
1811 tmp = _LOtransfer((char **) &destfd, inc, 1, (char **) &srcfd, 1, isDestLO);
1815 } while ((j = next_tuple(i + 1, indx, span)) != -1);
1820 _LOtransfer(char **destfd,
1827 #define MAX_READ (512 * 1024)
1828 #define min(a, b) (a < b ? a : b)
1829 struct varlena *v = NULL;
1834 inc = nitems * size;
1835 if (isSrcLO && isDestLO && inc > 0)
1836 for (tmp = 0, resid = inc;
1837 resid > 0 && (inc = min(resid, MAX_READ)) > 0; resid -= inc)
1840 v = (struct varlena *) LOread((int) *srcfd, inc);
1841 if (VARSIZE(v) - VARHDRSZ < inc)
1846 tmp += LOwrite((int) *destfd, v);
1851 else if (!isSrcLO && isDestLO)
1853 tmp = lo_write((int) *destfd, *srcfd, inc);
1854 *srcfd = *srcfd + tmp;
1856 else if (isSrcLO && !isDestLO)
1858 tmp = lo_read((int) *srcfd, *destfd, inc);
1859 *destfd = *destfd + tmp;
1863 memmove(*destfd, *srcfd, inc);
1873 _array_newLO(int *fd, int flag)
1876 char saveName[NAME_LEN];
1878 p = (char *) palloc(NAME_LEN);
1879 sprintf(p, "/Arry.%d", newoid());
1880 strcpy(saveName, p);
1882 if ((*fd = LOcreat(saveName, 0600, flag)) < 0)
1883 elog(ERROR, "Large object create failed");