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.3 1996/07/22 21:56:00 scrappy Exp $
12 *-------------------------------------------------------------------------
19 #include "catalog/catalog.h"
20 #include "catalog/pg_type.h"
22 #include "utils/syscache.h"
23 #include "utils/palloc.h"
24 #include "utils/memutils.h"
25 #include "storage/fd.h" /* for SEEK_ */
27 #include "utils/elog.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);
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,
50 static char *_ReadLOArray(char *str, int *nbytes, int *fd, bool *chunkFlag,
51 int ndim, int dim[], int baseSize);
52 static void _CopyArrayEls(char **values, char *p, int nitems, int typlen,
53 char typalign, bool typbyval);
54 static void system_cache_lookup(Oid element_type, bool input, int *typlen,
55 bool *typbyval, char *typdelim, Oid *typelem, Oid *proc,
57 static Datum _ArrayCast(char *value, bool byval, int len);
58 static char *_AdvanceBy1word(char *str, char **word);
59 static void _ArrayRange(int st[], int endp[], int bsize, char *destPtr,
60 ArrayType *array, int from);
61 static int _ArrayClipCount(int stI[], int endpI[], ArrayType *array);
62 static void _LOArrayRange(int st[], int endp[], int bsize, int srcfd,
63 int destfd, ArrayType *array, int isSrcLO, bool *isNull);
64 static void _ReadArray (int st[], int endp[], int bsize, int srcfd, int destfd,
65 ArrayType *array, int isDestLO, bool *isNull);
66 static char *_array_set(ArrayType *array, struct varlena *indx_str,
67 struct varlena *dataPtr);
68 static ArrayCastAndSet(char *src, bool typbyval, int typlen, char *dest);
71 /*---------------------------------------------------------------------
73 * converts an array from the external format in "string" to
76 * the internal representation of the input array
77 *--------------------------------------------------------------------
80 array_in(char *string, /* input array in external form */
81 Oid element_type) /* type OID of an array element */
88 char *string_save, *p, *q, *r;
94 int ndim, dim[MAXDIM], lBound[MAXDIM];
97 system_cache_lookup(element_type, true, &typlen, &typbyval, &typdelim,
98 &typelem, &typinput, &typalign);
100 fmgr_info(typinput, &inputproc, &dummy);
102 string_save = (char *) palloc(strlen(string) + 3);
103 strcpy(string_save, string);
105 /* --- read array dimensions ---------- */
106 p = q = string_save; done = false;
107 for ( ndim = 0; !done; ) {
108 while (isspace(*p)) p++;
111 if ((r = (char *)strchr(p, ':')) == (char *)NULL)
115 lBound[ndim] = atoi(p);
118 for (q = p; isdigit(*q); q++);
120 elog(WARN, "array_in: missing ']' in array declaration");
123 if ((dim[ndim] < 0) || (lBound[ndim] < 0))
124 elog(WARN,"array_in: array dimensions need to be positive");
125 dim[ndim] = dim[ndim] - lBound[ndim] + 1;
127 elog(WARN, "array_in: upper_bound cannot be < lower_bound");
136 ndim = _ArrayCount(p, dim, typdelim);
137 for (i = 0; i < ndim; lBound[i++] = 1);
139 elog(WARN,"array_in: Need to specify dimension");
142 while (isspace(*p)) p++;
143 if (strncmp(p, ASSGN, strlen(ASSGN)))
144 elog(WARN, "array_in: missing assignment operator");
146 while (isspace(*p)) p++;
149 nitems = getNitems( ndim, dim);
151 char *emptyArray = palloc(sizeof(ArrayType));
152 memset(emptyArray, 0, sizeof(ArrayType));
153 * (int32 *) emptyArray = sizeof(ArrayType);
158 /* array not a large object */
160 (char *) _ReadArrayStr(p, nitems, ndim, dim, inputproc, typelem,
161 typdelim, typlen, typbyval, typalign,
163 nbytes += ARR_OVERHEAD(ndim);
164 retval = (ArrayType *) palloc(nbytes);
165 memset(retval,0, nbytes);
166 memmove(retval, (char *)&nbytes, sizeof(int));
167 memmove((char*)ARR_NDIM_PTR(retval), (char *)&ndim, sizeof(int));
168 SET_LO_FLAG (false, retval);
169 memmove((char *)ARR_DIMS(retval), (char *)dim, ndim*sizeof(int));
170 memmove((char *)ARR_LBOUND(retval), (char *)lBound,
172 /* dataPtr is an array of arbitraystuff even though its type is char*
173 cast to char** to pass to _CopyArrayEls for now - jolly */
174 _CopyArrayEls((char**)dataPtr,
175 ARR_DATA_PTR(retval), nitems,
176 typlen, typalign, typbyval);
180 bool chunked = false;
182 dataPtr = _ReadLOArray(p, &bytes, &dummy, &chunked, ndim,
184 nbytes = bytes + ARR_OVERHEAD(ndim);
185 retval = (ArrayType *) palloc(nbytes);
186 memset(retval, 0,nbytes);
187 memmove(retval, (char *)&nbytes, sizeof(int));
188 memmove((char *)ARR_NDIM_PTR(retval), (char *)&ndim, sizeof(int));
189 SET_LO_FLAG (true, retval);
190 SET_CHUNK_FLAG (chunked, retval);
191 memmove((char *)ARR_DIMS(retval), (char *)dim, ndim*sizeof(int));
192 memmove((char *)ARR_LBOUND(retval),(char *)lBound, ndim*sizeof(int));
193 memmove(ARR_DATA_PTR(retval), dataPtr, bytes);
195 elog(WARN, "large object arrays not supported");
198 return((char *)retval);
201 /*-----------------------------------------------------------------------------
203 * Counts the number of dimensions and the dim[] array for an array string.
204 * The syntax for array input is C-like nested curly braces
205 *-----------------------------------------------------------------------------
208 _ArrayCount(char *str, int dim[], int typdelim)
210 int nest_level = 0, i;
211 int ndim = 0, temp[MAXDIM];
212 bool scanning_string = false;
213 bool eoArray = false;
216 for (i = 0; i < MAXDIM; ++i) {
217 temp[i] = dim[i] = 0;
220 if (strncmp (str, "{}", 2) == 0) return(0);
223 while (eoArray != true) {
229 /* skip escaped characters (\ and ") inside strings */
230 if (scanning_string && *(q+1)) {
236 scanning_string = ! scanning_string;
239 if (!scanning_string) {
240 temp[nest_level] = 0;
245 if (!scanning_string) {
246 if (!ndim) ndim = nest_level;
248 if (nest_level) temp[nest_level-1]++;
249 if (nest_level == 0) eoArray = done = true;
253 if (!ndim) ndim = nest_level;
254 if (*q == typdelim && !scanning_string )
263 while (isspace(*q)) q++;
265 for (i = 0; i < ndim; ++i) {
272 /*---------------------------------------------------------------------------
274 * parses the array string pointed by "arrayStr" and converts it in the
275 * internal format. The external format expected is like C array
276 * declaration. Unspecified elements are initialized to zero for fixed length
277 * base types and to empty varlena structures for variable length base
280 * returns the internal representation of the array elements
281 * nbytes is set to the size of the array in its internal representation.
282 *---------------------------------------------------------------------------
285 _ReadArrayStr(char *arrayStr,
289 func_ptr inputproc, /* function used for the conversion */
297 int i, nest_level = 0;
298 char *p, *q, *r, **values;
299 bool scanning_string = false;
300 int indx[MAXDIM], prod[MAXDIM];
301 bool eoArray = false;
303 mda_get_prod(ndim, dim, prod);
304 for (i = 0; i < ndim; indx[i++] = 0);
305 /* read array enclosed within {} */
306 values = (char **) palloc(nitems * sizeof(char *));
307 memset(values, 0, nitems * sizeof(char *));
310 while ( ! eoArray ) {
317 /* Crunch the string on top of the backslash. */
318 for (r = q; *r != '\0'; r++) *r = *(r+1);
321 if (!scanning_string ) {
323 p++; /* get p past first doublequote */
326 scanning_string = ! scanning_string;
329 if (!scanning_string) {
332 if (nest_level > ndim)
333 elog(WARN, "array_in: illformed array constant");
334 indx[nest_level - 1] = 0;
339 if (!scanning_string) {
341 i = tuple2linear(ndim, indx, prod);
344 eoArray = done = true;
347 indx[nest_level - 1]++;
352 if (*q == typdelim && !scanning_string ) {
354 i = tuple2linear(ndim, indx, prod);
365 elog(WARN, "array_in: illformed array constant");
366 values[i] = (*inputproc) (p, typelem);
370 * if not at the end of the array skip white space
372 while (isspace(*q)) {
378 *nbytes = nitems * typlen;
380 for (i = 0; i < nitems; i++)
382 values[i] = palloc(typlen);
383 memset(values[i], 0, typlen);
386 for (i = 0, *nbytes = 0; i < nitems; i++) {
389 *nbytes += DOUBLEALIGN(* (int32 *) values[i]);
391 *nbytes += INTALIGN(* (int32 *) values[i]);
394 *nbytes += sizeof(int32);
395 values[i] = palloc(sizeof(int32));
396 *(int32 *)values[i] = sizeof(int32);
400 return((char *)values);
404 /*----------------------------------------------------------------------------
405 * Read data about an array to be stored as a large object
406 *----------------------------------------------------------------------------
409 _ReadLOArray(char *str,
417 char *inputfile, *accessfile = NULL, *chunkfile = NULL;
418 char *retStr, *_AdvanceBy1word();
421 str = _AdvanceBy1word(str, &inputfile);
423 while (str != NULL) {
426 str = _AdvanceBy1word(str, &word);
428 if (!strcmp (word, "-chunk")) {
430 elog(WARN, "array_in: access pattern file required");
431 str = _AdvanceBy1word(str, &accessfile);
433 else if (!strcmp (word, "-noreorg")) {
435 elog(WARN, "array_in: chunk file required");
436 str = _AdvanceBy1word(str, &chunkfile);
438 elog(WARN, "usage: <input file> -chunk DEFAULT/<access pattern file> -invert/-native [-noreorg <chunk file>]");
442 if (inputfile == NULL)
443 elog(WARN, "array_in: missing file name");
444 lobjId = lo_creat(0);
445 *fd = lo_open(lobjId, INV_READ);
447 elog(WARN, "Large object create failed");
449 *nbytes = strlen(retStr) + 2;
453 if ((afd = fopen (accessfile, "r")) == NULL)
454 elog(WARN, "unable to open access pattern file");
456 retStr = _ChunkArray(*fd, afd, ndim, dim, baseSize, nbytes,
463 _CopyArrayEls(char **values,
472 for (i = 0; i < nitems; i++) {
474 inc = ArrayCastAndSet(values[i], typbyval, typlen, p);
482 /*-------------------------------------------------------------------------
484 * takes the internal representation of an array and returns a string
485 * containing the array in its external format.
486 *-------------------------------------------------------------------------
489 array_out(ArrayType *v, Oid element_type)
494 Oid typoutput, typelem;
498 char *p, *retval, **values, delim[2];
499 int nitems, overall_length, i, j, k, indx[MAXDIM];
504 if (v == (ArrayType *) NULL)
505 return ((char *) NULL);
507 if (ARR_IS_LO(v) == true) {
511 /* get a wide string to print to */
512 p = array_dims(v, &dummy_bool);
513 nbytes = strlen(ARR_DATA_PTR(v)) + 4 + *(int *)p;
515 save_p = (char *) palloc(nbytes);
517 strcpy(save_p, p + sizeof(int));
518 strcat(save_p, ASSGN);
519 strcat(save_p, ARR_DATA_PTR(v));
524 system_cache_lookup(element_type, false, &typlen, &typbyval,
525 &typdelim, &typelem, &typoutput, &typalign);
526 fmgr_info(typoutput, & outputproc, &dummy_int);
527 sprintf(delim, "%c", typdelim);
530 nitems = getNitems(ndim, dim);
533 char *emptyArray = palloc(3);
536 emptyArray[2] = '\0';
541 overall_length = 1; /* [TRH] don't forget to count \0 at end. */
542 values = (char **) palloc(nitems * sizeof (char *));
543 for (i = 0; i < nitems; i++) {
547 values[i] = (*outputproc) (*p, typelem);
550 values[i] = (*outputproc) (* (int16 *) p, typelem);
554 values[i] = (*outputproc) (* (int32 *) p, typelem);
559 values[i] = (*outputproc) (p, typelem);
563 p += INTALIGN(* (int32 *) p);
565 * For the pair of double quotes
569 overall_length += (strlen(values[i]) + 1);
573 * count total number of curly braces in output string
575 for (i = j = 0, k = 1; i < ndim; k *= dim[i++], j += k);
577 p = (char *) palloc(overall_length + 2*j);
581 for (i = 0; i < ndim; indx[i++] = 0);
584 for (i = j; i < ndim - 1; i++)
587 * Surround anything that is not passed by value in double quotes.
588 * See above for more details.
592 strcat(p, values[k]);
595 strcat(p, values[k]);
598 for (i = ndim - 1; i >= 0; i--) {
599 indx[i] = (indx[i] + 1)%dim[i];
613 /*-----------------------------------------------------------------------------
615 * returns the dimension of the array pointed to by "v"
616 *----------------------------------------------------------------------------
619 array_dims(ArrayType *v, bool *isNull)
625 if (v == (ArrayType *) NULL) RETURN_NULL;
626 nbytes = ARR_NDIM(v)*33;
628 * 33 since we assume 15 digits per number + ':' +'[]'
630 save_p = p = (char *) palloc(nbytes + 4);
631 memset(save_p, 0, nbytes + 4);
632 dimv = ARR_DIMS(v); lb = ARR_LBOUND(v);
634 for (i = 0; i < ARR_NDIM(v); i++) {
635 sprintf(p, "[%d:%d]", lb[i], dimv[i]+lb[i]-1);
638 nbytes = strlen(save_p + 4) + 4;
639 memmove(save_p, &nbytes,4);
643 /*---------------------------------------------------------------------------
645 * This routing takes an array pointer and an index array and returns
646 * a pointer to the referred element if element is passed by
647 * reference otherwise returns the value of the referred element.
648 *---------------------------------------------------------------------------
651 array_ref(ArrayType *array,
659 int i, ndim, *dim, *lb, offset, nbytes;
663 if (array == (ArrayType *) NULL) RETURN_NULL;
666 * fixed length arrays -- these are assumed to be 1-d
668 if (indx[0]*elmlen > arraylen)
669 elog(WARN, "array_ref: array bound exceeded");
670 retval = (char *)array + indx[0]*elmlen;
671 return _ArrayCast(retval, reftype, elmlen);
673 dim = ARR_DIMS(array);
674 lb = ARR_LBOUND(array);
675 ndim = ARR_NDIM(array);
676 nbytes = (* (int32 *) array) - ARR_OVERHEAD(ndim);
678 if (!SanityCheckInput(ndim, n, dim, lb, indx))
681 offset = GetOffset(n, dim, lb, indx);
683 if (ARR_IS_LO(array)) {
687 /* We are assuming fixed element lengths here */
689 lo_name = (char *)ARR_DATA_PTR(array);
691 if ((fd = LOopen(lo_name, ARR_IS_INV(array)?INV_READ:O_RDONLY)) < 0)
694 if (ARR_IS_CHUNKED(array))
695 v = _ReadChunkArray1El(indx, elmlen, fd, array, isNull);
697 if (lo_lseek(fd, offset, SEEK_SET) < 0)
700 v = (struct varlena *) LOread(fd, elmlen);
703 if (*isNull) RETURN_NULL;
704 if (VARSIZE(v) - 4 < elmlen)
707 retval = (char *)_ArrayCast((char *)VARDATA(v), reftype, elmlen);
708 if ( reftype == 0) { /* not by value */
709 char * tempdata = palloc (elmlen);
710 memmove(tempdata, retval, elmlen);
714 return (Datum) retval;
718 offset = offset * elmlen;
719 /* off the end of the array */
720 if (nbytes - offset < 1) RETURN_NULL;
721 retval = ARR_DATA_PTR (array) + offset;
722 return _ArrayCast(retval, reftype, elmlen);
727 temp = ARR_DATA_PTR (array);
729 while (bytes > 0 && !done) {
734 bytes -= INTALIGN(* (int32 *) temp);
735 temp += INTALIGN(* (int32 *) temp);
740 return (Datum) retval;
744 /*-----------------------------------------------------------------------------
746 * This routine takes an array and a range of indices (upperIndex and
747 * lowerIndx), creates a new array structure for the referred elements
748 * and returns a pointer to it.
749 *-----------------------------------------------------------------------------
752 array_clip(ArrayType *array,
760 int i, ndim, *dim, *lb, nbytes;
762 int bytes, span[MAXDIM];
765 if (array == (ArrayType *) NULL)
767 dim = ARR_DIMS(array);
768 lb = ARR_LBOUND(array);
769 ndim = ARR_NDIM(array);
770 nbytes = (* (int32 *) array) - ARR_OVERHEAD(ndim);
772 if (!SanityCheckInput(ndim, n, dim, lb, upperIndx))
775 if (!SanityCheckInput(ndim, n, dim, lb, lowerIndx))
778 for (i = 0; i < n; i++)
779 if (lowerIndx[i] > upperIndx[i])
780 elog(WARN, "lowerIndex cannot be larger than upperIndx");
781 mda_get_range(n, span, lowerIndx, upperIndx);
783 if (ARR_IS_LO(array)) {
784 char * lo_name, * newname;
785 int fd, newfd, isDestLO = true, rsize;
788 elog(WARN, "array_clip: array of variable length objects not supported");
790 lo_name = (char *)ARR_DATA_PTR(array);
791 if ((fd = LOopen(lo_name, ARR_IS_INV(array)?INV_READ:O_RDONLY)) < 0)
793 newname = _array_newLO( &newfd, Unix );
795 bytes = strlen(newname) + 1 + ARR_OVERHEAD(n);
796 newArr = (ArrayType *) palloc(bytes);
797 memmove(newArr, array, sizeof(ArrayType));
798 memmove(newArr, &bytes, sizeof(int));
799 memmove(ARR_DIMS(newArr), span, n*sizeof(int));
800 memmove(ARR_LBOUND(newArr), lowerIndx, n*sizeof(int));
801 strcpy(ARR_DATA_PTR(newArr), newname);
803 rsize = compute_size (lowerIndx, upperIndx, n, len);
804 if (rsize < MAX_BUFF_SIZE) {
807 buff = palloc(rsize);
810 if (ARR_IS_CHUNKED(array)) {
811 _ReadChunkArray(lowerIndx, upperIndx, len, fd, &(buff[4]),
814 _ReadArray(lowerIndx, upperIndx, len, fd, (int)&(buff[4]),
818 memmove(buff, &rsize, 4);
821 bytes = LOwrite(newfd, (struct varlena *)buff);
826 if (ARR_IS_CHUNKED(array)) {
827 _ReadChunkArray(lowerIndx, upperIndx, len, fd, (char*)newfd, array,
830 _ReadArray(lowerIndx, upperIndx, len, fd, newfd, array, 1,isNull);
834 (void) LOclose(newfd);
841 return ((Datum) newArr);
845 bytes = getNitems(n, span);
846 bytes = bytes*len + ARR_OVERHEAD(n);
848 bytes = _ArrayClipCount(lowerIndx, upperIndx, array);
849 bytes += ARR_OVERHEAD(n);
851 newArr = (ArrayType *) palloc(bytes);
852 memmove(newArr, array, sizeof(ArrayType));
853 memmove(newArr, &bytes, sizeof(int));
854 memmove(ARR_DIMS(newArr), span, n*sizeof(int));
855 memmove(ARR_LBOUND(newArr), lowerIndx, n*sizeof(int));
856 _ArrayRange(lowerIndx, upperIndx, len, ARR_DATA_PTR(newArr), array, 1);
857 return (Datum) newArr;
860 /*-----------------------------------------------------------------------------
862 * This routine sets the value of an array location (specified by an index array)
863 * to a new value specified by "dataPtr".
865 * returns a pointer to the modified array.
866 *-----------------------------------------------------------------------------
869 array_set(ArrayType *array,
878 int ndim, *dim, *lb, offset, nbytes;
881 if (array == (ArrayType *) NULL)
885 * fixed length arrays -- these are assumed to be 1-d
887 if (indx[0]*elmlen > arraylen)
889 elog(WARN, "array_ref: array bound exceeded");
891 elog(WARN, "array_set: array bound exceeded");
893 pos = (char *)array + indx[0]*elmlen;
894 ArrayCastAndSet(dataPtr, (bool) reftype, elmlen, pos);
895 return((char *)array);
897 dim = ARR_DIMS(array);
898 lb = ARR_LBOUND(array);
899 ndim = ARR_NDIM(array);
900 nbytes = (* (int32 *) array) - ARR_OVERHEAD(ndim);
902 if (!SanityCheckInput(ndim, n, dim, lb, indx))
905 elog(WARN, "array_set: array bound exceeded");
906 return((char *)array);
909 return((char *)array);
911 offset = GetOffset( n, dim, lb, indx);
913 if (ARR_IS_LO(array)) {
918 /* We are assuming fixed element lengths here */
921 lo_name = ARR_DATA_PTR(array);
922 if ((fd = LOopen(lo_name, ARR_IS_INV(array)?INV_WRITE:O_WRONLY)) < 0)
923 return((char *)array);
925 if (lo_lseek(fd, offset, SEEK_SET) < 0)
926 return((char *)array);
927 v = (struct varlena *) palloc(elmlen + 4);
928 VARSIZE (v) = elmlen + 4;
929 ArrayCastAndSet(dataPtr, (bool) reftype, elmlen, VARDATA(v));
933 /* if (n < VARSIZE(v) - 4)
938 return((char *)array);
941 offset = offset * elmlen;
942 /* off the end of the array */
943 if (nbytes - offset < 1) return((char *)array);
944 pos = ARR_DATA_PTR (array) + offset;
949 int oldsize, newsize, oldlen, newlen, lth0, lth1, lth2;
951 elt_ptr = array_seek(ARR_DATA_PTR(array), -1, offset);
952 oldlen = INTALIGN(*(int32 *)elt_ptr);
953 newlen = INTALIGN(*(int32 *)dataPtr);
955 if (oldlen == newlen) {
956 /* new element with same size, overwrite old data */
957 ArrayCastAndSet(dataPtr, (bool)reftype, elmlen, elt_ptr);
958 return((char *)array);
961 /* new element with different size, reallocate the array */
962 oldsize = array->size;
963 lth0 = ARR_OVERHEAD(n);
964 lth1 = (int)(elt_ptr - ARR_DATA_PTR(array));
965 lth2 = (int)(oldsize - lth0 - lth1 - oldlen);
966 newsize = lth0 + lth1 + newlen + lth2;
968 newarray = (ArrayType *)palloc(newsize);
969 memmove((char *)newarray, (char *)array, lth0+lth1);
970 newarray->size = newsize;
971 newlen = ArrayCastAndSet(dataPtr, (bool)reftype, elmlen,
972 (char *)newarray+lth0+lth1);
973 memmove((char *)newarray+lth0+lth1+newlen,
974 (char *)array+lth0+lth1+oldlen, lth2);
976 /* ??? who should free this storage ??? */
977 return((char *)newarray);
979 elog(WARN, "array_set: update of variable length fields not supported");
982 ArrayCastAndSet(dataPtr, (bool) reftype, elmlen, pos);
983 return((char *)array);
986 /*----------------------------------------------------------------------------
988 * This routine sets the value of a range of array locations (specified
989 * by upper and lower index values ) to new values passed as
992 * returns a pointer to the modified array.
993 *----------------------------------------------------------------------------
996 array_assgn(ArrayType *array,
1005 int i, ndim, *dim, *lb;
1007 if (array == (ArrayType *) NULL)
1010 elog(WARN,"array_assgn:updates on arrays of variable length elements not allowed");
1012 dim = ARR_DIMS(array);
1013 lb = ARR_LBOUND(array);
1014 ndim = ARR_NDIM(array);
1016 if (!SanityCheckInput(ndim, n, dim, lb, upperIndx) ||
1017 !SanityCheckInput(ndim, n, dim, lb, lowerIndx)) {
1018 return((char *)array);
1021 for (i = 0; i < n; i++)
1022 if (lowerIndx[i] > upperIndx[i])
1023 elog(WARN, "lowerIndex larger than upperIndx");
1025 if (ARR_IS_LO(array)) {
1030 lo_name = (char *)ARR_DATA_PTR(array);
1031 if ((fd = LOopen(lo_name, ARR_IS_INV(array)?INV_WRITE:O_WRONLY)) < 0)
1032 return((char *)array);
1034 if (ARR_IS_LO(newArr)) {
1036 lo_name = (char *)ARR_DATA_PTR(newArr);
1037 if ((newfd = LOopen(lo_name, ARR_IS_INV(newArr)?INV_READ:O_RDONLY)) < 0)
1038 return((char *)array);
1040 _LOArrayRange(lowerIndx, upperIndx, len, fd, newfd, array, 1, isNull);
1041 (void) lo_close(newfd);
1043 _LOArrayRange(lowerIndx, upperIndx, len, fd, (int)ARR_DATA_PTR(newArr),
1046 (void) lo_close(fd);
1047 return ((char *) array);
1049 _ArrayRange(lowerIndx, upperIndx, len, ARR_DATA_PTR(newArr), array, 0);
1050 return (char *) array;
1053 /*-----------------------------------------------------------------------------
1055 * compares two arrays for equality
1057 * returns 1 if the arrays are equal, 0 otherwise.
1058 *-----------------------------------------------------------------------------
1061 array_eq (ArrayType *array1, ArrayType *array2)
1063 if ((array1 == NULL) || (array2 == NULL))
1065 if (*(int *)array1 != *(int *)array2)
1067 if (memcmp(array1, array2, *(int *)array1))
1072 /***************************************************************************/
1073 /******************| Support Routines |*****************/
1074 /***************************************************************************/
1076 system_cache_lookup(Oid element_type,
1085 HeapTuple typeTuple;
1086 TypeTupleForm typeStruct;
1088 typeTuple = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(element_type),
1091 if (!HeapTupleIsValid(typeTuple)) {
1092 elog(WARN, "array_out: Cache lookup failed for type %d\n",
1096 typeStruct = (TypeTupleForm) GETSTRUCT(typeTuple);
1097 *typlen = typeStruct->typlen;
1098 *typbyval = typeStruct->typbyval;
1099 *typdelim = typeStruct->typdelim;
1100 *typelem = typeStruct->typelem;
1101 *typalign = typeStruct->typalign;
1103 *proc = typeStruct->typinput;
1105 *proc = typeStruct->typoutput;
1110 _ArrayCast(char *value, bool byval, int len)
1115 return((Datum) * value);
1117 return((Datum) * (int16 *) value);
1120 return((Datum) * (int32 *) value);
1122 elog(WARN, "array_ref: byval and elt len > 4!");
1126 return (Datum) value;
1133 ArrayCastAndSet(char *src,
1144 *dest = DatumGetChar(src);
1147 * (int16 *) dest = DatumGetInt16(src);
1150 * (int32 *) dest = (int32)src;
1154 memmove(dest, src, typlen);
1158 memmove(dest, src, *(int32 *)src);
1159 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) {
1183 SanityCheckInput(int ndim, int n, int dim[], int lb[], int indx[])
1186 /* Do Sanity check on input */
1187 if (n != ndim) return 0;
1188 for (i = 0; i < ndim; i++)
1189 if ((lb[i] > indx[i]) || (indx[i] >= (dim[i] + lb[i])))
1195 _ArrayRange(int st[],
1202 int n, *dim, *lb, st_pos, prod[MAXDIM];
1203 int span[MAXDIM], dist[MAXDIM], indx[MAXDIM];
1205 char *srcPtr, *array_seek();
1207 n = ARR_NDIM(array); dim = ARR_DIMS(array);
1208 lb = ARR_LBOUND(array); srcPtr = ARR_DATA_PTR(array);
1209 for (i = 0; i < n; st[i] -= lb[i], endp[i] -= lb[i], i++);
1210 mda_get_prod(n, dim, prod);
1211 st_pos = tuple2linear(n, st, prod);
1212 srcPtr = array_seek(srcPtr, bsize, st_pos);
1213 mda_get_range(n, span, st, endp);
1214 mda_get_offset_values(n, dist, prod, span);
1215 for (i=0; i < n; indx[i++]=0);
1216 i = j = n-1; inc = bsize;
1218 srcPtr = array_seek(srcPtr, bsize, dist[j]);
1220 inc = array_read(destPtr, bsize, 1, srcPtr);
1222 inc = array_read(srcPtr, bsize, 1, destPtr);
1223 destPtr += inc; srcPtr += inc;
1224 } while ((j = next_tuple(i+1, indx, span)) != -1);
1228 _ArrayClipCount(int stI[], int endpI[], ArrayType *array)
1230 int n, *dim, *lb, st_pos, prod[MAXDIM];
1231 int span[MAXDIM], dist[MAXDIM], indx[MAXDIM];
1232 int i, j, inc, st[MAXDIM], endp[MAXDIM];
1234 char *ptr, *array_seek();
1236 n = ARR_NDIM(array); dim = ARR_DIMS(array);
1237 lb = ARR_LBOUND(array); ptr = ARR_DATA_PTR(array);
1238 for (i = 0; i < n; st[i] = stI[i]-lb[i], endp[i]=endpI[i]-lb[i], i++);
1239 mda_get_prod(n, dim, prod);
1240 st_pos = tuple2linear(n, st, prod);
1241 ptr = array_seek(ptr, -1, st_pos);
1242 mda_get_range(n, span, st, endp);
1243 mda_get_offset_values(n, dist, prod, span);
1244 for (i=0; i < n; indx[i++]=0);
1247 ptr = array_seek(ptr, -1, dist[j]);
1248 inc = INTALIGN(* (int32 *) ptr);
1249 ptr += inc; count += inc;
1250 } while ((j = next_tuple(i+1, indx, span)) != -1);
1255 array_seek(char *ptr, int eltsize, int nitems)
1260 return(ptr + eltsize*nitems);
1261 for (i = 0; i < nitems; i++)
1262 ptr += INTALIGN(* (int32 *) ptr);
1267 array_read(char *destptr, int eltsize, int nitems, char *srcptr)
1272 memmove(destptr, srcptr, eltsize*nitems);
1273 return(eltsize*nitems);
1275 for (i = inc = 0; i < nitems; i++) {
1276 tmp = (INTALIGN(* (int32 *) srcptr));
1277 memmove(destptr, srcptr, tmp);
1286 _LOArrayRange(int st[],
1295 int n, *dim, st_pos, prod[MAXDIM];
1296 int span[MAXDIM], dist[MAXDIM], indx[MAXDIM];
1297 int i, j, inc, tmp, *lb, offset;
1299 n = ARR_NDIM(array); dim = ARR_DIMS(array);
1300 lb = ARR_LBOUND(array);
1301 for (i = 0; i < n; st[i] -= lb[i], endp[i] -= lb[i], i++);
1303 mda_get_prod(n, dim, prod);
1304 st_pos = tuple2linear(n, st, prod);
1305 offset = st_pos*bsize;
1306 if (lo_lseek(srcfd, offset, SEEK_SET) < 0)
1308 mda_get_range(n, span, st, endp);
1309 mda_get_offset_values(n, dist, prod, span);
1310 for (i=0; i < n; indx[i++]=0);
1311 for (i = n-1, inc = bsize; i >= 0; inc *= span[i--])
1316 offset += (dist[j]*bsize);
1317 if (lo_lseek(srcfd, offset, SEEK_SET) < 0)
1319 tmp = _LOtransfer((char**)&srcfd, inc, 1, (char**)&destfd, isSrcLO, 1);
1323 } while ((j = next_tuple(i+1, indx, span)) != -1);
1328 _ReadArray (int st[],
1337 int n, *dim, st_pos, prod[MAXDIM];
1338 int span[MAXDIM], dist[MAXDIM], indx[MAXDIM];
1339 int i, j, inc, tmp, *lb, offset;
1341 n = ARR_NDIM(array); dim = ARR_DIMS(array);
1342 lb = ARR_LBOUND(array);
1343 for (i = 0; i < n; st[i] -= lb[i], endp[i] -= lb[i], i++);
1345 mda_get_prod(n, dim, prod);
1346 st_pos = tuple2linear(n, st, prod);
1347 offset = st_pos*bsize;
1348 if (lo_lseek(srcfd, offset, SEEK_SET) < 0)
1350 mda_get_range(n, span, st, endp);
1351 mda_get_offset_values(n, dist, prod, span);
1352 for (i=0; i < n; indx[i++]=0);
1353 for (i = n-1, inc = bsize; i >= 0; inc *= span[i--])
1358 offset += (dist[j]*bsize);
1359 if (lo_lseek(srcfd, offset, SEEK_SET) < 0)
1361 tmp = _LOtransfer((char**)&destfd, inc, 1, (char**)&srcfd, 1, isDestLO);
1365 } while ((j = next_tuple(i+1, indx, span)) != -1);
1370 _LOtransfer(char **destfd,
1377 #define MAX_READ (512 * 1024)
1378 #define min(a, b) (a < b ? a : b)
1380 int tmp, inc, resid;
1383 if (isSrcLO && isDestLO && inc > 0)
1384 for (tmp = 0, resid = inc;
1385 resid > 0 && (inc = min(resid, MAX_READ)) > 0; resid -= inc) {
1387 v = (struct varlena *) LOread((int) *srcfd, inc);
1388 if (VARSIZE(v) - 4 < inc)
1389 {pfree(v); return(-1);}
1390 tmp += LOwrite((int) *destfd, v);
1395 else if (!isSrcLO && isDestLO) {
1396 tmp = lo_write((int) *destfd, *srcfd, inc);
1397 *srcfd = *srcfd + tmp;
1399 else if (isSrcLO && !isDestLO) {
1400 tmp = lo_read((int) *srcfd, *destfd, inc);
1401 *destfd = *destfd + tmp;
1404 memmove(*destfd, *srcfd, inc);
1414 _array_newLO(int *fd, int flag)
1417 char saveName[NAME_LEN];
1419 p = (char *) palloc(NAME_LEN);
1420 sprintf(p, "/Arry.%d", newoid());
1421 strcpy (saveName, p);
1423 if ( (*fd = LOcreat (saveName, 0600, flag)) < 0)
1424 elog(WARN, "Large object create failed");