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.11 1997/07/24 20:15:45 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" /* for SEEK_ */
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);
46 static char *_ReadArrayStr(char *arrayStr, int nitems, int ndim, int dim[],
47 func_ptr inputproc, Oid typelem, char typdelim,
48 int typlen, bool typbyval, char typalign,
51 static char *_ReadLOArray(char *str, int *nbytes, int *fd, bool *chunkFlag,
52 int ndim, int dim[], int baseSize);
54 static void _CopyArrayEls(char **values, char *p, int nitems, int typlen,
55 char typalign, bool typbyval);
56 static void system_cache_lookup(Oid element_type, bool input, int *typlen,
57 bool *typbyval, char *typdelim, Oid *typelem, Oid *proc,
59 static Datum _ArrayCast(char *value, bool byval, int len);
61 static char *_AdvanceBy1word(char *str, char **word);
63 static void _ArrayRange(int st[], int endp[], int bsize, char *destPtr,
64 ArrayType *array, int from);
65 static int _ArrayClipCount(int stI[], int endpI[], ArrayType *array);
66 static void _LOArrayRange(int st[], int endp[], int bsize, int srcfd,
67 int destfd, ArrayType *array, int isSrcLO, bool *isNull);
68 static void _ReadArray (int st[], int endp[], int bsize, int srcfd, int destfd,
69 ArrayType *array, int isDestLO, bool *isNull);
70 static ArrayCastAndSet(char *src, bool typbyval, int typlen, char *dest);
73 /*---------------------------------------------------------------------
75 * converts an array from the external format in "string" to
78 * the internal representation of the input array
79 *--------------------------------------------------------------------
82 array_in(char *string, /* input array in external form */
83 Oid element_type) /* type OID of an array element */
90 char *string_save, *p, *q, *r;
95 ArrayType *retval = NULL;
96 int ndim, dim[MAXDIM], lBound[MAXDIM];
99 system_cache_lookup(element_type, true, &typlen, &typbyval, &typdelim,
100 &typelem, &typinput, &typalign);
102 fmgr_info(typinput, &inputproc, &dummy);
104 string_save = (char *) palloc(strlen(string) + 3);
105 strcpy(string_save, string);
107 /* --- read array dimensions ---------- */
108 p = q = string_save; done = false;
109 for ( ndim = 0; !done; ) {
110 while (isspace(*p)) p++;
113 if ((r = (char *)strchr(p, ':')) == (char *)NULL)
117 lBound[ndim] = atoi(p);
120 for (q = p; isdigit(*q); q++);
122 elog(WARN, "array_in: missing ']' in array declaration");
125 if ((dim[ndim] < 0) || (lBound[ndim] < 0))
126 elog(WARN,"array_in: array dimensions need to be positive");
127 dim[ndim] = dim[ndim] - lBound[ndim] + 1;
129 elog(WARN, "array_in: upper_bound cannot be < lower_bound");
138 ndim = _ArrayCount(p, dim, typdelim);
139 for (i = 0; i < ndim; lBound[i++] = 1);
141 elog(WARN,"array_in: Need to specify dimension");
144 while (isspace(*p)) p++;
145 if (strncmp(p, ASSGN, strlen(ASSGN)))
146 elog(WARN, "array_in: missing assignment operator");
148 while (isspace(*p)) p++;
151 nitems = getNitems( ndim, dim);
153 char *emptyArray = palloc(sizeof(ArrayType));
154 memset(emptyArray, 0, sizeof(ArrayType));
155 * (int32 *) emptyArray = sizeof(ArrayType);
160 /* array not a large object */
162 (char *) _ReadArrayStr(p, nitems, ndim, dim, inputproc, typelem,
163 typdelim, typlen, typbyval, typalign,
165 nbytes += ARR_OVERHEAD(ndim);
166 retval = (ArrayType *) palloc(nbytes);
167 memset(retval,0, nbytes);
168 memmove(retval, (char *)&nbytes, sizeof(int));
169 memmove((char*)ARR_NDIM_PTR(retval), (char *)&ndim, sizeof(int));
170 SET_LO_FLAG (false, retval);
171 memmove((char *)ARR_DIMS(retval), (char *)dim, ndim*sizeof(int));
172 memmove((char *)ARR_LBOUND(retval), (char *)lBound,
174 /* dataPtr is an array of arbitraystuff even though its type is char*
175 cast to char** to pass to _CopyArrayEls for now - jolly */
176 _CopyArrayEls((char**)dataPtr,
177 ARR_DATA_PTR(retval), nitems,
178 typlen, typalign, typbyval);
182 bool chunked = false;
184 dataPtr = _ReadLOArray(p, &bytes, &dummy, &chunked, ndim,
186 nbytes = bytes + ARR_OVERHEAD(ndim);
187 retval = (ArrayType *) palloc(nbytes);
188 memset(retval, 0,nbytes);
189 memmove(retval, (char *)&nbytes, sizeof(int));
190 memmove((char *)ARR_NDIM_PTR(retval), (char *)&ndim, sizeof(int));
191 SET_LO_FLAG (true, retval);
192 SET_CHUNK_FLAG (chunked, retval);
193 memmove((char *)ARR_DIMS(retval), (char *)dim, ndim*sizeof(int));
194 memmove((char *)ARR_LBOUND(retval),(char *)lBound, ndim*sizeof(int));
195 memmove(ARR_DATA_PTR(retval), dataPtr, bytes);
197 elog(WARN, "large object arrays not supported");
200 return((char *)retval);
203 /*-----------------------------------------------------------------------------
205 * Counts the number of dimensions and the dim[] array for an array string.
206 * The syntax for array input is C-like nested curly braces
207 *-----------------------------------------------------------------------------
210 _ArrayCount(char *str, int dim[], int typdelim)
212 int nest_level = 0, i;
213 int ndim = 0, temp[MAXDIM];
214 bool scanning_string = false;
215 bool eoArray = false;
218 for (i = 0; i < MAXDIM; ++i) {
219 temp[i] = dim[i] = 0;
222 if (strncmp (str, "{}", 2) == 0) return(0);
225 while (eoArray != true) {
230 /* skip escaped characters (\ and ") inside strings */
231 if (scanning_string && *(q+1)) {
236 /* Signal a premature end of the string. DZ - 2-9-1996 */
237 elog(WARN, "malformed array constant: %s", str);
240 scanning_string = ! scanning_string;
243 if (!scanning_string) {
244 temp[nest_level] = 0;
249 if (!scanning_string) {
250 if (!ndim) ndim = nest_level;
252 if (nest_level) temp[nest_level-1]++;
253 if (nest_level == 0) eoArray = done = true;
257 if (!ndim) ndim = nest_level;
258 if (*q == typdelim && !scanning_string )
267 while (isspace(*q)) q++;
269 for (i = 0; i < ndim; ++i) {
276 /*---------------------------------------------------------------------------
278 * parses the array string pointed by "arrayStr" and converts it in the
279 * internal format. The external format expected is like C array
280 * declaration. Unspecified elements are initialized to zero for fixed length
281 * base types and to empty varlena structures for variable length base
284 * returns the internal representation of the array elements
285 * nbytes is set to the size of the array in its internal representation.
286 *---------------------------------------------------------------------------
289 _ReadArrayStr(char *arrayStr,
293 func_ptr inputproc, /* function used for the conversion */
301 int i, nest_level = 0;
302 char *p, *q, *r, **values;
303 bool scanning_string = false;
304 int indx[MAXDIM], prod[MAXDIM];
305 bool eoArray = false;
307 mda_get_prod(ndim, dim, prod);
308 for (i = 0; i < ndim; indx[i++] = 0);
309 /* read array enclosed within {} */
310 values = (char **) palloc(nitems * sizeof(char *));
311 memset(values, 0, nitems * sizeof(char *));
314 while ( ! eoArray ) {
321 /* Crunch the string on top of the backslash. */
322 for (r = q; *r != '\0'; r++) *r = *(r+1);
325 if (!scanning_string ) {
327 p++; /* get p past first doublequote */
330 scanning_string = ! scanning_string;
333 if (!scanning_string) {
336 if (nest_level > ndim)
337 elog(WARN, "array_in: illformed array constant");
338 indx[nest_level - 1] = 0;
343 if (!scanning_string) {
345 i = tuple2linear(ndim, indx, prod);
348 eoArray = done = true;
351 indx[nest_level - 1]++;
356 if (*q == typdelim && !scanning_string ) {
358 i = tuple2linear(ndim, indx, prod);
369 elog(WARN, "array_in: illformed array constant");
370 values[i] = (*inputproc) (p, typelem);
374 * if not at the end of the array skip white space
376 while (isspace(*q)) {
382 *nbytes = nitems * typlen;
384 for (i = 0; i < nitems; i++)
386 values[i] = palloc(typlen);
387 memset(values[i], 0, typlen);
390 for (i = 0, *nbytes = 0; i < nitems; i++) {
393 *nbytes += DOUBLEALIGN(* (int32 *) values[i]);
395 *nbytes += INTALIGN(* (int32 *) values[i]);
398 *nbytes += sizeof(int32);
399 values[i] = palloc(sizeof(int32));
400 *(int32 *)values[i] = sizeof(int32);
404 return((char *)values);
408 /*----------------------------------------------------------------------------
409 * Read data about an array to be stored as a large object
410 *----------------------------------------------------------------------------
414 _ReadLOArray(char *str,
422 char *inputfile, *accessfile = NULL, *chunkfile = NULL;
423 char *retStr, *_AdvanceBy1word();
426 str = _AdvanceBy1word(str, &inputfile);
428 while (str != NULL) {
431 str = _AdvanceBy1word(str, &word);
433 if (!strcmp (word, "-chunk")) {
435 elog(WARN, "array_in: access pattern file required");
436 str = _AdvanceBy1word(str, &accessfile);
438 else if (!strcmp (word, "-noreorg")) {
440 elog(WARN, "array_in: chunk file required");
441 str = _AdvanceBy1word(str, &chunkfile);
443 elog(WARN, "usage: <input file> -chunk DEFAULT/<access pattern file> -invert/-native [-noreorg <chunk file>]");
447 if (inputfile == NULL)
448 elog(WARN, "array_in: missing file name");
449 lobjId = lo_creat(0);
450 *fd = lo_open(lobjId, INV_READ);
452 elog(WARN, "Large object create failed");
454 *nbytes = strlen(retStr) + 2;
458 if ((afd = fopen (accessfile, "r")) == NULL)
459 elog(WARN, "unable to open access pattern file");
461 retStr = _ChunkArray(*fd, afd, ndim, dim, baseSize, nbytes,
469 _CopyArrayEls(char **values,
478 for (i = 0; i < nitems; i++) {
480 inc = ArrayCastAndSet(values[i], typbyval, typlen, p);
488 /*-------------------------------------------------------------------------
490 * takes the internal representation of an array and returns a string
491 * containing the array in its external format.
492 *-------------------------------------------------------------------------
495 array_out(ArrayType *v, Oid element_type)
500 Oid typoutput, typelem;
504 char *p, *retval, **values, delim[2];
505 int nitems, overall_length, i, j, k, indx[MAXDIM];
510 if (v == (ArrayType *) NULL)
511 return ((char *) NULL);
513 if (ARR_IS_LO(v) == true) {
517 /* get a wide string to print to */
518 p = array_dims(v, &dummy_bool);
519 nbytes = strlen(ARR_DATA_PTR(v)) + 4 + *(int *)p;
521 save_p = (char *) palloc(nbytes);
523 strcpy(save_p, p + sizeof(int));
524 strcat(save_p, ASSGN);
525 strcat(save_p, ARR_DATA_PTR(v));
530 system_cache_lookup(element_type, false, &typlen, &typbyval,
531 &typdelim, &typelem, &typoutput, &typalign);
532 fmgr_info(typoutput, & outputproc, &dummy_int);
533 sprintf(delim, "%c", typdelim);
536 nitems = getNitems(ndim, dim);
539 char *emptyArray = palloc(3);
542 emptyArray[2] = '\0';
547 overall_length = 1; /* [TRH] don't forget to count \0 at end. */
548 values = (char **) palloc(nitems * sizeof (char *));
549 for (i = 0; i < nitems; i++) {
553 values[i] = (*outputproc) (*p, typelem);
556 values[i] = (*outputproc) (* (int16 *) p, typelem);
560 values[i] = (*outputproc) (* (int32 *) p, typelem);
565 values[i] = (*outputproc) (p, typelem);
569 p += INTALIGN(* (int32 *) p);
571 * For the pair of double quotes
575 overall_length += (strlen(values[i]) + 1);
579 * count total number of curly braces in output string
581 for (i = j = 0, k = 1; i < ndim; k *= dim[i++], j += k);
583 p = (char *) palloc(overall_length + 2*j);
587 for (i = 0; i < ndim; indx[i++] = 0);
590 for (i = j; i < ndim - 1; i++)
593 * Surround anything that is not passed by value in double quotes.
594 * See above for more details.
598 strcat(p, values[k]);
601 strcat(p, values[k]);
604 for (i = ndim - 1; i >= 0; i--) {
605 indx[i] = (indx[i] + 1)%dim[i];
619 /*-----------------------------------------------------------------------------
621 * returns the dimension of the array pointed to by "v"
622 *----------------------------------------------------------------------------
625 array_dims(ArrayType *v, bool *isNull)
631 if (v == (ArrayType *) NULL) RETURN_NULL;
632 nbytes = ARR_NDIM(v)*33;
634 * 33 since we assume 15 digits per number + ':' +'[]'
636 save_p = p = (char *) palloc(nbytes + 4);
637 memset(save_p, 0, nbytes + 4);
638 dimv = ARR_DIMS(v); lb = ARR_LBOUND(v);
640 for (i = 0; i < ARR_NDIM(v); i++) {
641 sprintf(p, "[%d:%d]", lb[i], dimv[i]+lb[i]-1);
644 nbytes = strlen(save_p + 4) + 4;
645 memmove(save_p, &nbytes,4);
649 /*---------------------------------------------------------------------------
651 * This routing takes an array pointer and an index array and returns
652 * a pointer to the referred element if element is passed by
653 * reference otherwise returns the value of the referred element.
654 *---------------------------------------------------------------------------
657 array_ref(ArrayType *array,
665 int i, ndim, *dim, *lb, offset, nbytes;
666 struct varlena *v = NULL;
669 if (array == (ArrayType *) NULL) RETURN_NULL;
672 * fixed length arrays -- these are assumed to be 1-d
674 if (indx[0]*elmlen > arraylen)
675 elog(WARN, "array_ref: array bound exceeded");
676 retval = (char *)array + indx[0]*elmlen;
677 return _ArrayCast(retval, reftype, elmlen);
679 dim = ARR_DIMS(array);
680 lb = ARR_LBOUND(array);
681 ndim = ARR_NDIM(array);
682 nbytes = (* (int32 *) array) - ARR_OVERHEAD(ndim);
684 if (!SanityCheckInput(ndim, n, dim, lb, indx))
687 offset = GetOffset(n, dim, lb, indx);
689 if (ARR_IS_LO(array)) {
693 /* We are assuming fixed element lengths here */
695 lo_name = (char *)ARR_DATA_PTR(array);
697 if ((fd = LOopen(lo_name, ARR_IS_INV(array)?INV_READ:O_RDONLY)) < 0)
700 if (ARR_IS_CHUNKED(array))
701 v = _ReadChunkArray1El(indx, elmlen, fd, array, isNull);
703 if (lo_lseek(fd, offset, SEEK_SET) < 0)
706 v = (struct varlena *) LOread(fd, elmlen);
709 if (*isNull) RETURN_NULL;
710 if (VARSIZE(v) - 4 < elmlen)
713 retval = (char *)_ArrayCast((char *)VARDATA(v), reftype, elmlen);
714 if ( reftype == 0) { /* not by value */
715 char * tempdata = palloc (elmlen);
716 memmove(tempdata, retval, elmlen);
720 return (Datum) retval;
724 offset = offset * elmlen;
725 /* off the end of the array */
726 if (nbytes - offset < 1) RETURN_NULL;
727 retval = ARR_DATA_PTR (array) + offset;
728 return _ArrayCast(retval, reftype, elmlen);
733 temp = ARR_DATA_PTR (array);
735 while (bytes > 0 && !done) {
740 bytes -= INTALIGN(* (int32 *) temp);
741 temp += INTALIGN(* (int32 *) temp);
746 return (Datum) retval;
750 /*-----------------------------------------------------------------------------
752 * This routine takes an array and a range of indices (upperIndex and
753 * lowerIndx), creates a new array structure for the referred elements
754 * and returns a pointer to it.
755 *-----------------------------------------------------------------------------
758 array_clip(ArrayType *array,
766 int i, ndim, *dim, *lb, nbytes;
768 int bytes, span[MAXDIM];
771 if (array == (ArrayType *) NULL)
773 dim = ARR_DIMS(array);
774 lb = ARR_LBOUND(array);
775 ndim = ARR_NDIM(array);
776 nbytes = (* (int32 *) array) - ARR_OVERHEAD(ndim);
778 if (!SanityCheckInput(ndim, n, dim, lb, upperIndx))
781 if (!SanityCheckInput(ndim, n, dim, lb, lowerIndx))
784 for (i = 0; i < n; i++)
785 if (lowerIndx[i] > upperIndx[i])
786 elog(WARN, "lowerIndex cannot be larger than upperIndx");
787 mda_get_range(n, span, lowerIndx, upperIndx);
789 if (ARR_IS_LO(array)) {
793 char *newname = NULL;
794 int fd = 0, newfd = 0, isDestLO = true, rsize;
797 elog(WARN, "array_clip: array of variable length objects not supported");
799 lo_name = (char *)ARR_DATA_PTR(array);
800 if ((fd = LOopen(lo_name, ARR_IS_INV(array)?INV_READ:O_RDONLY)) < 0)
802 newname = _array_newLO( &newfd, Unix );
804 bytes = strlen(newname) + 1 + ARR_OVERHEAD(n);
805 newArr = (ArrayType *) palloc(bytes);
806 memmove(newArr, array, sizeof(ArrayType));
807 memmove(newArr, &bytes, sizeof(int));
808 memmove(ARR_DIMS(newArr), span, n*sizeof(int));
809 memmove(ARR_LBOUND(newArr), lowerIndx, n*sizeof(int));
810 strcpy(ARR_DATA_PTR(newArr), newname);
812 rsize = compute_size (lowerIndx, upperIndx, n, len);
813 if (rsize < MAX_BUFF_SIZE) {
816 buff = palloc(rsize);
819 if (ARR_IS_CHUNKED(array)) {
820 _ReadChunkArray(lowerIndx, upperIndx, len, fd, &(buff[4]),
823 _ReadArray(lowerIndx, upperIndx, len, fd, (int)&(buff[4]),
827 memmove(buff, &rsize, 4);
830 bytes = LOwrite(newfd, (struct varlena *)buff);
835 if (ARR_IS_CHUNKED(array)) {
836 _ReadChunkArray(lowerIndx, upperIndx, len, fd, (char*)newfd, array,
839 _ReadArray(lowerIndx, upperIndx, len, fd, newfd, array, 1,isNull);
843 (void) LOclose(newfd);
850 return ((Datum) newArr);
854 bytes = getNitems(n, span);
855 bytes = bytes*len + ARR_OVERHEAD(n);
857 bytes = _ArrayClipCount(lowerIndx, upperIndx, array);
858 bytes += ARR_OVERHEAD(n);
860 newArr = (ArrayType *) palloc(bytes);
861 memmove(newArr, array, sizeof(ArrayType));
862 memmove(newArr, &bytes, sizeof(int));
863 memmove(ARR_DIMS(newArr), span, n*sizeof(int));
864 memmove(ARR_LBOUND(newArr), lowerIndx, n*sizeof(int));
865 _ArrayRange(lowerIndx, upperIndx, len, ARR_DATA_PTR(newArr), array, 1);
866 return (Datum) newArr;
869 /*-----------------------------------------------------------------------------
871 * This routine sets the value of an array location (specified by an index array)
872 * to a new value specified by "dataPtr".
874 * returns a pointer to the modified array.
875 *-----------------------------------------------------------------------------
878 array_set(ArrayType *array,
887 int ndim, *dim, *lb, offset, nbytes;
890 if (array == (ArrayType *) NULL)
894 * fixed length arrays -- these are assumed to be 1-d
896 if (indx[0]*elmlen > arraylen)
897 elog(WARN, "array_ref: array bound exceeded");
898 pos = (char *)array + indx[0]*elmlen;
899 ArrayCastAndSet(dataPtr, (bool) reftype, elmlen, pos);
900 return((char *)array);
902 dim = ARR_DIMS(array);
903 lb = ARR_LBOUND(array);
904 ndim = ARR_NDIM(array);
905 nbytes = (* (int32 *) array) - ARR_OVERHEAD(ndim);
907 if (!SanityCheckInput(ndim, n, dim, lb, indx))
909 elog(WARN, "array_set: array bound exceeded");
910 return((char *)array);
912 offset = GetOffset( n, dim, lb, indx);
914 if (ARR_IS_LO(array)) {
918 /* We are assuming fixed element lengths here */
923 lo_name = ARR_DATA_PTR(array);
924 if ((fd = LOopen(lo_name, ARR_IS_INV(array)?INV_WRITE:O_WRONLY)) < 0)
925 return((char *)array);
927 if (lo_lseek(fd, offset, SEEK_SET) < 0)
928 return((char *)array);
929 v = (struct varlena *) palloc(elmlen + 4);
930 VARSIZE (v) = elmlen + 4;
931 ArrayCastAndSet(dataPtr, (bool) reftype, elmlen, VARDATA(v));
935 /* if (n < VARSIZE(v) - 4)
940 return((char *)array);
943 offset = offset * elmlen;
944 /* off the end of the array */
945 if (nbytes - offset < 1) return((char *)array);
946 pos = ARR_DATA_PTR (array) + offset;
950 int oldsize, newsize, oldlen, newlen, lth0, lth1, lth2;
952 elt_ptr = array_seek(ARR_DATA_PTR(array), -1, offset);
953 oldlen = INTALIGN(*(int32 *)elt_ptr);
954 newlen = INTALIGN(*(int32 *)dataPtr);
956 if (oldlen == newlen) {
957 /* new element with same size, overwrite old data */
958 ArrayCastAndSet(dataPtr, (bool)reftype, elmlen, elt_ptr);
959 return((char *)array);
962 /* new element with different size, reallocate the array */
963 oldsize = array->size;
964 lth0 = ARR_OVERHEAD(n);
965 lth1 = (int)(elt_ptr - ARR_DATA_PTR(array));
966 lth2 = (int)(oldsize - lth0 - lth1 - oldlen);
967 newsize = lth0 + lth1 + newlen + lth2;
969 newarray = (ArrayType *)palloc(newsize);
970 memmove((char *)newarray, (char *)array, lth0+lth1);
971 newarray->size = newsize;
972 newlen = ArrayCastAndSet(dataPtr, (bool)reftype, elmlen,
973 (char *)newarray+lth0+lth1);
974 memmove((char *)newarray+lth0+lth1+newlen,
975 (char *)array+lth0+lth1+oldlen, lth2);
977 /* ??? who should free this storage ??? */
978 return((char *)newarray);
980 ArrayCastAndSet(dataPtr, (bool) reftype, elmlen, pos);
981 return((char *)array);
984 /*----------------------------------------------------------------------------
986 * This routine sets the value of a range of array locations (specified
987 * by upper and lower index values ) to new values passed as
990 * returns a pointer to the modified array.
991 *----------------------------------------------------------------------------
994 array_assgn(ArrayType *array,
1003 int i, ndim, *dim, *lb;
1005 if (array == (ArrayType *) NULL)
1008 elog(WARN,"array_assgn:updates on arrays of variable length elements not allowed");
1010 dim = ARR_DIMS(array);
1011 lb = ARR_LBOUND(array);
1012 ndim = ARR_NDIM(array);
1014 if (!SanityCheckInput(ndim, n, dim, lb, upperIndx) ||
1015 !SanityCheckInput(ndim, n, dim, lb, lowerIndx)) {
1016 return((char *)array);
1019 for (i = 0; i < n; i++)
1020 if (lowerIndx[i] > upperIndx[i])
1021 elog(WARN, "lowerIndex larger than upperIndx");
1023 if (ARR_IS_LO(array)) {
1024 int fd = 0, newfd = 0;
1029 lo_name = (char *)ARR_DATA_PTR(array);
1030 if ((fd = LOopen(lo_name, ARR_IS_INV(array)?INV_WRITE:O_WRONLY)) < 0)
1031 return((char *)array);
1033 if (ARR_IS_LO(newArr)) {
1035 lo_name = (char *)ARR_DATA_PTR(newArr);
1036 if ((newfd = LOopen(lo_name, ARR_IS_INV(newArr)?INV_READ:O_RDONLY)) < 0)
1037 return((char *)array);
1039 _LOArrayRange(lowerIndx, upperIndx, len, fd, newfd, array, 1, isNull);
1040 (void) lo_close(newfd);
1042 _LOArrayRange(lowerIndx, upperIndx, len, fd, (int)ARR_DATA_PTR(newArr),
1045 (void) lo_close(fd);
1046 return ((char *) array);
1048 _ArrayRange(lowerIndx, upperIndx, len, ARR_DATA_PTR(newArr), array, 0);
1049 return (char *) array;
1052 /*-----------------------------------------------------------------------------
1054 * compares two arrays for equality
1056 * returns 1 if the arrays are equal, 0 otherwise.
1057 *-----------------------------------------------------------------------------
1060 array_eq (ArrayType *array1, ArrayType *array2)
1062 if ((array1 == NULL) || (array2 == NULL))
1064 if (*(int *)array1 != *(int *)array2)
1066 if (memcmp(array1, array2, *(int *)array1))
1071 /***************************************************************************/
1072 /******************| Support Routines |*****************/
1073 /***************************************************************************/
1075 system_cache_lookup(Oid element_type,
1084 HeapTuple typeTuple;
1085 TypeTupleForm typeStruct;
1087 typeTuple = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(element_type),
1090 if (!HeapTupleIsValid(typeTuple)) {
1091 elog(WARN, "array_out: Cache lookup failed for type %d\n",
1095 typeStruct = (TypeTupleForm) GETSTRUCT(typeTuple);
1096 *typlen = typeStruct->typlen;
1097 *typbyval = typeStruct->typbyval;
1098 *typdelim = typeStruct->typdelim;
1099 *typelem = typeStruct->typelem;
1100 *typalign = typeStruct->typalign;
1102 *proc = typeStruct->typinput;
1104 *proc = typeStruct->typoutput;
1109 _ArrayCast(char *value, bool byval, int len)
1114 return((Datum) * value);
1116 return((Datum) * (int16 *) value);
1119 return((Datum) * (int32 *) value);
1121 elog(WARN, "array_ref: byval and elt len > 4!");
1125 return (Datum) value;
1132 ArrayCastAndSet(char *src,
1143 *dest = DatumGetChar(src);
1146 * (int16 *) dest = DatumGetInt16(src);
1149 * (int32 *) dest = (int32)src;
1153 memmove(dest, src, typlen);
1157 memmove(dest, src, *(int32 *)src);
1158 inc = (INTALIGN(* (int32 *) src));
1165 _AdvanceBy1word(char *str, char **word)
1167 char *retstr, *space;
1170 if (str == NULL) return str;
1171 while (isspace(*str)) str++;
1173 if ((space = (char *)strchr(str, ' ')) != (char *) NULL) {
1184 SanityCheckInput(int ndim, int n, int dim[], int lb[], int indx[])
1187 /* Do Sanity check on input */
1188 if (n != ndim) return 0;
1189 for (i = 0; i < ndim; i++)
1190 if ((lb[i] > indx[i]) || (indx[i] >= (dim[i] + lb[i])))
1196 _ArrayRange(int st[],
1203 int n, *dim, *lb, st_pos, prod[MAXDIM];
1204 int span[MAXDIM], dist[MAXDIM], indx[MAXDIM];
1208 n = ARR_NDIM(array); dim = ARR_DIMS(array);
1209 lb = ARR_LBOUND(array); srcPtr = ARR_DATA_PTR(array);
1210 for (i = 0; i < n; st[i] -= lb[i], endp[i] -= lb[i], i++);
1211 mda_get_prod(n, dim, prod);
1212 st_pos = tuple2linear(n, st, prod);
1213 srcPtr = array_seek(srcPtr, bsize, st_pos);
1214 mda_get_range(n, span, st, endp);
1215 mda_get_offset_values(n, dist, prod, span);
1216 for (i=0; i < n; indx[i++]=0);
1217 i = j = n-1; inc = bsize;
1219 srcPtr = array_seek(srcPtr, bsize, dist[j]);
1221 inc = array_read(destPtr, bsize, 1, srcPtr);
1223 inc = array_read(srcPtr, bsize, 1, destPtr);
1224 destPtr += inc; srcPtr += inc;
1225 } while ((j = next_tuple(i+1, indx, span)) != -1);
1229 _ArrayClipCount(int stI[], int endpI[], ArrayType *array)
1231 int n, *dim, *lb, st_pos, prod[MAXDIM];
1232 int span[MAXDIM], dist[MAXDIM], indx[MAXDIM];
1233 int i, j, inc, st[MAXDIM], endp[MAXDIM];
1237 n = ARR_NDIM(array); dim = ARR_DIMS(array);
1238 lb = ARR_LBOUND(array); ptr = ARR_DATA_PTR(array);
1239 for (i = 0; i < n; st[i] = stI[i]-lb[i], endp[i]=endpI[i]-lb[i], i++);
1240 mda_get_prod(n, dim, prod);
1241 st_pos = tuple2linear(n, st, prod);
1242 ptr = array_seek(ptr, -1, st_pos);
1243 mda_get_range(n, span, st, endp);
1244 mda_get_offset_values(n, dist, prod, span);
1245 for (i=0; i < n; indx[i++]=0);
1248 ptr = array_seek(ptr, -1, dist[j]);
1249 inc = INTALIGN(* (int32 *) ptr);
1250 ptr += inc; count += inc;
1251 } while ((j = next_tuple(i+1, indx, span)) != -1);
1256 array_seek(char *ptr, int eltsize, int nitems)
1261 return(ptr + eltsize*nitems);
1262 for (i = 0; i < nitems; i++)
1263 ptr += INTALIGN(* (int32 *) ptr);
1268 array_read(char *destptr, int eltsize, int nitems, char *srcptr)
1273 memmove(destptr, srcptr, eltsize*nitems);
1274 return(eltsize*nitems);
1276 for (i = inc = 0; i < nitems; i++) {
1277 tmp = (INTALIGN(* (int32 *) srcptr));
1278 memmove(destptr, srcptr, tmp);
1287 _LOArrayRange(int st[],
1296 int n, *dim, st_pos, prod[MAXDIM];
1297 int span[MAXDIM], dist[MAXDIM], indx[MAXDIM];
1298 int i, j, inc, tmp, *lb, offset;
1300 n = ARR_NDIM(array); dim = ARR_DIMS(array);
1301 lb = ARR_LBOUND(array);
1302 for (i = 0; i < n; st[i] -= lb[i], endp[i] -= lb[i], i++);
1304 mda_get_prod(n, dim, prod);
1305 st_pos = tuple2linear(n, st, prod);
1306 offset = st_pos*bsize;
1307 if (lo_lseek(srcfd, offset, SEEK_SET) < 0)
1309 mda_get_range(n, span, st, endp);
1310 mda_get_offset_values(n, dist, prod, span);
1311 for (i=0; i < n; indx[i++]=0);
1312 for (i = n-1, inc = bsize; i >= 0; inc *= span[i--])
1317 offset += (dist[j]*bsize);
1318 if (lo_lseek(srcfd, offset, SEEK_SET) < 0)
1320 tmp = _LOtransfer((char**)&srcfd, inc, 1, (char**)&destfd, isSrcLO, 1);
1324 } while ((j = next_tuple(i+1, indx, span)) != -1);
1329 _ReadArray (int st[],
1338 int n, *dim, st_pos, prod[MAXDIM];
1339 int span[MAXDIM], dist[MAXDIM], indx[MAXDIM];
1340 int i, j, inc, tmp, *lb, offset;
1342 n = ARR_NDIM(array); dim = ARR_DIMS(array);
1343 lb = ARR_LBOUND(array);
1344 for (i = 0; i < n; st[i] -= lb[i], endp[i] -= lb[i], i++);
1346 mda_get_prod(n, dim, prod);
1347 st_pos = tuple2linear(n, st, prod);
1348 offset = st_pos*bsize;
1349 if (lo_lseek(srcfd, offset, SEEK_SET) < 0)
1351 mda_get_range(n, span, st, endp);
1352 mda_get_offset_values(n, dist, prod, span);
1353 for (i=0; i < n; indx[i++]=0);
1354 for (i = n-1, inc = bsize; i >= 0; inc *= span[i--])
1359 offset += (dist[j]*bsize);
1360 if (lo_lseek(srcfd, offset, SEEK_SET) < 0)
1362 tmp = _LOtransfer((char**)&destfd, inc, 1, (char**)&srcfd, 1, isDestLO);
1366 } while ((j = next_tuple(i+1, indx, span)) != -1);
1371 _LOtransfer(char **destfd,
1378 #define MAX_READ (512 * 1024)
1379 #define min(a, b) (a < b ? a : b)
1380 struct varlena *v = NULL;
1381 int tmp, inc, resid;
1384 if (isSrcLO && isDestLO && inc > 0)
1385 for (tmp = 0, resid = inc;
1386 resid > 0 && (inc = min(resid, MAX_READ)) > 0; resid -= inc) {
1388 v = (struct varlena *) LOread((int) *srcfd, inc);
1389 if (VARSIZE(v) - 4 < inc)
1390 {pfree(v); return(-1);}
1391 tmp += LOwrite((int) *destfd, v);
1396 else if (!isSrcLO && isDestLO) {
1397 tmp = lo_write((int) *destfd, *srcfd, inc);
1398 *srcfd = *srcfd + tmp;
1400 else if (isSrcLO && !isDestLO) {
1401 tmp = lo_read((int) *srcfd, *destfd, inc);
1402 *destfd = *destfd + tmp;
1405 memmove(*destfd, *srcfd, inc);
1415 _array_newLO(int *fd, int flag)
1418 char saveName[NAME_LEN];
1420 p = (char *) palloc(NAME_LEN);
1421 sprintf(p, "/Arry.%d", newoid());
1422 strcpy (saveName, p);
1424 if ( (*fd = LOcreat (saveName, 0600, flag)) < 0)
1425 elog(WARN, "Large object create failed");