1 /*-------------------------------------------------------------------------
4 * Special functions for arrays.
6 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.57 2000/06/13 07:35:03 tgl Exp $
13 *-------------------------------------------------------------------------
20 #include "catalog/catalog.h"
21 #include "catalog/pg_type.h"
23 #include "libpq/be-fsstubs.h"
24 #include "libpq/libpq-fs.h"
25 #include "storage/fd.h"
26 #include "utils/array.h"
27 #include "utils/memutils.h"
28 #include "utils/syscache.h"
32 /* An array has the following internal structure:
33 * <nbytes> - total number of bytes
34 * <ndim> - number of dimensions of the array
35 * <flags> - bit mask of flags
36 * <dim> - size of each array axis
37 * <dim_lower> - lower boundary of each dimension
38 * <actual data> - whatever is the stored data
41 /*-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-*/
42 static int _ArrayCount(char *str, int *dim, int typdelim);
43 static char *_ReadArrayStr(char *arrayStr, int nitems, int ndim, int *dim,
44 FmgrInfo *inputproc, Oid typelem, int32 typmod,
45 char typdelim, int typlen, bool typbyval,
46 char typalign, int *nbytes);
49 static char *_ReadLOArray(char *str, int *nbytes, int *fd, bool *chunkFlag,
50 int ndim, int *dim, int baseSize);
53 static void _CopyArrayEls(char **values, char *p, int nitems, int typlen,
54 char typalign, bool typbyval);
55 static void system_cache_lookup(Oid element_type, bool input, int *typlen,
56 bool *typbyval, char *typdelim, Oid *typelem, Oid *proc,
58 static Datum _ArrayCast(char *value, bool byval, int len);
61 static char *_AdvanceBy1word(char *str, char **word);
64 static void _ArrayRange(int *st, int *endp, int bsize, char *destPtr,
65 ArrayType *array, int from);
66 static int _ArrayClipCount(int *stI, int *endpI, ArrayType *array);
67 static void _LOArrayRange(int *st, int *endp, int bsize, int srcfd,
68 int destfd, ArrayType *array, int isSrcLO, bool *isNull);
69 static void _ReadArray(int *st, int *endp, int bsize, int srcfd, int destfd,
70 ArrayType *array, int isDestLO, bool *isNull);
71 static int ArrayCastAndSet(Datum src, bool typbyval, int typlen, char *dest);
72 static int SanityCheckInput(int ndim, int n, int *dim, int *lb, int *indx);
73 static int array_read(char *destptr, int eltsize, int nitems, char *srcptr);
74 static char *array_seek(char *ptr, int eltsize, int nitems);
76 /*---------------------------------------------------------------------
78 * converts an array from the external format in "string" to
79 * its internal format.
81 * the internal representation of the input array
82 *--------------------------------------------------------------------
85 array_in(PG_FUNCTION_ARGS)
87 char *string = PG_GETARG_CSTRING(0); /* external form */
88 Oid element_type = PG_GETARG_OID(1); /* type of an array element */
89 int32 typmod = PG_GETARG_INT32(2); /* typmod for array elements */
111 system_cache_lookup(element_type, true, &typlen, &typbyval, &typdelim,
112 &typelem, &typinput, &typalign);
114 fmgr_info(typinput, &inputproc);
116 string_save = (char *) palloc(strlen(string) + 3);
117 strcpy(string_save, string);
119 /* --- read array dimensions ---------- */
122 for (ndim = 0; !done;)
129 if ((r = (char *) strchr(p, ':')) == (char *) NULL)
134 lBound[ndim] = atoi(p);
137 for (q = p; isdigit(*q); q++);
139 elog(ERROR, "array_in: missing ']' in array declaration");
142 if ((dim[ndim] < 0) || (lBound[ndim] < 0))
143 elog(ERROR, "array_in: array dimensions need to be positive");
144 dim[ndim] = dim[ndim] - lBound[ndim] + 1;
146 elog(ERROR, "array_in: upper_bound cannot be < lower_bound");
158 ndim = _ArrayCount(p, dim, typdelim);
159 for (i = 0; i < ndim; lBound[i++] = 1);
162 elog(ERROR, "array_in: Need to specify dimension");
168 if (strncmp(p, ASSGN, strlen(ASSGN)))
169 elog(ERROR, "array_in: missing assignment operator");
176 printf("array_in- ndim %d (", ndim);
177 for (i = 0; i < ndim; i++)
179 printf(" %d", dim[i]);
181 printf(") for %s\n", string);
184 nitems = getNitems(ndim, dim);
187 retval = (ArrayType *) palloc(sizeof(ArrayType));
188 MemSet(retval, 0, sizeof(ArrayType));
189 *(int32 *) retval = sizeof(ArrayType);
190 return PointerGetDatum(retval);
195 /* array not a large object */
196 dataPtr = (char *) _ReadArrayStr(p, nitems, ndim, dim, &inputproc, typelem,
197 typmod, typdelim, typlen, typbyval, typalign,
199 nbytes += ARR_OVERHEAD(ndim);
200 retval = (ArrayType *) palloc(nbytes);
201 MemSet(retval, 0, nbytes);
202 memmove(retval, (char *) &nbytes, sizeof(int));
203 memmove((char *) ARR_NDIM_PTR(retval), (char *) &ndim, sizeof(int));
204 SET_LO_FLAG(false, retval);
205 memmove((char *) ARR_DIMS(retval), (char *) dim, ndim * sizeof(int));
206 memmove((char *) ARR_LBOUND(retval), (char *) lBound,
210 * dataPtr is an array of arbitraystuff even though its type is
211 * char* cast to char** to pass to _CopyArrayEls for now - jolly
213 _CopyArrayEls((char **) dataPtr,
214 ARR_DATA_PTR(retval), nitems,
215 typlen, typalign, typbyval);
222 bool chunked = false;
224 dataPtr = _ReadLOArray(p, &bytes, &dummy, &chunked, ndim,
226 nbytes = bytes + ARR_OVERHEAD(ndim);
227 retval = (ArrayType *) palloc(nbytes);
228 MemSet(retval, 0, nbytes);
229 memmove(retval, (char *) &nbytes, sizeof(int));
230 memmove((char *) ARR_NDIM_PTR(retval), (char *) &ndim, sizeof(int));
231 SET_LO_FLAG(true, retval);
232 SET_CHUNK_FLAG(chunked, retval);
233 memmove((char *) ARR_DIMS(retval), (char *) dim, ndim * sizeof(int));
234 memmove((char *) ARR_LBOUND(retval), (char *) lBound, ndim * sizeof(int));
235 memmove(ARR_DATA_PTR(retval), dataPtr, bytes);
237 elog(ERROR, "large object arrays not supported");
241 return PointerGetDatum(retval);
244 /*-----------------------------------------------------------------------------
246 * Counts the number of dimensions and the *dim array for an array string.
247 * The syntax for array input is C-like nested curly braces
248 *-----------------------------------------------------------------------------
251 _ArrayCount(char *str, int *dim, int typdelim)
257 bool scanning_string = false;
258 bool eoArray = false;
261 for (i = 0; i < MAXDIM; ++i)
262 temp[i] = dim[i] = 0;
264 if (strncmp(str, "{}", 2) == 0)
268 while (eoArray != true)
277 /* skip escaped characters (\ and ") inside strings */
278 if (scanning_string && *(q + 1))
284 * Signal a premature end of the string. DZ -
287 elog(ERROR, "malformed array constant: %s", str);
290 scanning_string = !scanning_string;
293 if (!scanning_string)
295 temp[nest_level] = 0;
300 if (!scanning_string)
306 temp[nest_level - 1]++;
308 eoArray = done = true;
314 if (*q == typdelim && !scanning_string)
327 for (i = 0; i < ndim; ++i)
333 /*---------------------------------------------------------------------------
335 * parses the array string pointed by "arrayStr" and converts it in the
336 * internal format. The external format expected is like C array
337 * declaration. Unspecified elements are initialized to zero for fixed length
338 * base types and to empty varlena structures for variable length base
341 * returns the internal representation of the array elements
342 * nbytes is set to the size of the array in its internal representation.
343 *---------------------------------------------------------------------------
346 _ReadArrayStr(char *arrayStr,
350 FmgrInfo *inputproc, /* function used for the
366 bool scanning_string = false;
369 bool eoArray = false;
371 mda_get_prod(ndim, dim, prod);
372 for (i = 0; i < ndim; indx[i++] = 0);
373 /* read array enclosed within {} */
374 values = (char **) palloc(nitems * sizeof(char *));
375 MemSet(values, 0, nitems * sizeof(char *));
388 /* Crunch the string on top of the backslash. */
389 for (r = q; *r != '\0'; r++)
393 if (!scanning_string)
397 p++; /* get p past first doublequote */
401 scanning_string = !scanning_string;
404 if (!scanning_string)
408 if (nest_level > ndim)
409 elog(ERROR, "array_in: illformed array constant");
410 indx[nest_level - 1] = 0;
415 if (!scanning_string)
418 i = tuple2linear(ndim, indx, prod);
421 eoArray = done = true;
425 indx[nest_level - 1]++;
430 if (*q == typdelim && !scanning_string)
433 i = tuple2linear(ndim, indx, prod);
444 elog(ERROR, "array_in: illformed array constant");
445 values[i] = (char *) FunctionCall3(inputproc,
447 ObjectIdGetDatum(typelem),
448 Int32GetDatum(typmod));
453 * if not at the end of the array skip white space
463 *nbytes = nitems * typlen;
465 for (i = 0; i < nitems; i++)
468 values[i] = palloc(typlen);
469 MemSet(values[i], 0, typlen);
474 for (i = 0, *nbytes = 0; i < nitems; i++)
479 *nbytes += MAXALIGN(*(int32 *) values[i]);
481 *nbytes += INTALIGN(*(int32 *) values[i]);
485 *nbytes += sizeof(int32);
486 values[i] = palloc(sizeof(int32));
487 *(int32 *) values[i] = sizeof(int32);
491 return (char *) values;
495 /*----------------------------------------------------------------------------
496 * Read data about an array to be stored as a large object
497 *----------------------------------------------------------------------------
501 _ReadLOArray(char *str,
516 str = _AdvanceBy1word(str, &inputfile);
522 str = _AdvanceBy1word(str, &word);
524 if (!strcmp(word, "-chunk"))
527 elog(ERROR, "array_in: access pattern file required");
528 str = _AdvanceBy1word(str, &accessfile);
530 else if (!strcmp(word, "-noreorg"))
533 elog(ERROR, "array_in: chunk file required");
534 str = _AdvanceBy1word(str, &chunkfile);
537 elog(ERROR, "usage: <input file> -chunk DEFAULT/<access pattern file> -invert/-native [-noreorg <chunk file>]");
540 if (inputfile == NULL)
541 elog(ERROR, "array_in: missing file name");
542 lobjId = DatumGetObjectId(DirectFunctionCall1(lo_creat,
544 *fd = DatumGetInt32(DirectFunctionCall2(lo_open,
545 ObjectIdGetDatum(lobjId),
546 Int32GetDatum(INV_READ)));
548 elog(ERROR, "Large object create failed");
550 *nbytes = strlen(retStr) + 2;
556 if ((afd = AllocateFile(accessfile, PG_BINARY_R)) == NULL)
557 elog(ERROR, "unable to open access pattern file");
559 retStr = _ChunkArray(*fd, afd, ndim, dim, baseSize, nbytes,
569 _CopyArrayEls(char **values,
578 for (i = 0; i < nitems; i++)
582 inc = ArrayCastAndSet((Datum) values[i], typbyval, typlen, p);
590 /*-------------------------------------------------------------------------
592 * takes the internal representation of an array and returns a string
593 * containing the array in its external format.
594 *-------------------------------------------------------------------------
597 array_out(PG_FUNCTION_ARGS)
599 ArrayType *v = (ArrayType *) PG_GETARG_VARLENA_P(0);
600 Oid element_type = PG_GETARG_OID(1);
625 if (v == (ArrayType *) NULL)
626 PG_RETURN_CSTRING((char *) NULL);
628 if (ARR_IS_LO(v) == true)
634 p = (text *) DatumGetPointer(DirectFunctionCall1(array_dims,
635 PointerGetDatum(v)));
636 plen = VARSIZE(p) - VARHDRSZ;
638 /* get a wide string to print to */
639 nbytes = strlen(ARR_DATA_PTR(v)) + strlen(ASSGN) + plen + 1;
640 retval = (char *) palloc(nbytes);
642 memcpy(retval, VARDATA(p), plen);
643 strcpy(retval + plen, ASSGN);
644 strcat(retval, ARR_DATA_PTR(v));
646 PG_RETURN_CSTRING(retval);
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 retval = (char *) palloc(3);
663 PG_RETURN_CSTRING(retval);
667 overall_length = 1; /* [TRH] don't forget to count \0 at end. */
668 values = (char **) palloc(nitems * sizeof(char *));
669 for (i = 0; i < nitems; i++)
676 values[i] = DatumGetCString(FunctionCall3(&outputproc,
678 ObjectIdGetDatum(typelem),
682 values[i] = DatumGetCString(FunctionCall3(&outputproc,
683 Int16GetDatum(*(int16 *) p),
684 ObjectIdGetDatum(typelem),
689 values[i] = DatumGetCString(FunctionCall3(&outputproc,
690 Int32GetDatum(*(int32 *) p),
691 ObjectIdGetDatum(typelem),
699 values[i] = DatumGetCString(FunctionCall3(&outputproc,
701 ObjectIdGetDatum(typelem),
706 p += INTALIGN(*(int32 *) p);
709 * For the pair of double quotes
713 for (tmp = values[i]; *tmp; tmp++)
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.
750 for (tmp = values[k]; *tmp; tmp++)
758 strcat(p, values[k]);
763 strcat(p, values[k]);
766 for (i = ndim - 1; i >= 0; i--)
768 indx[i] = (indx[i] + 1) % dim[i];
781 PG_RETURN_CSTRING(retval);
784 /*-----------------------------------------------------------------------------
786 * returns the dimensions of the array pointed to by "v", as a "text"
787 *----------------------------------------------------------------------------
790 array_dims(PG_FUNCTION_ARGS)
792 ArrayType *v = (ArrayType *) PG_GETARG_VARLENA_P(0);
800 nbytes = ARR_NDIM(v) * 33 + 1;
802 * 33 since we assume 15 digits per number + ':' +'[]'
804 * +1 allows for temp trailing null
807 result = (text *) palloc(nbytes + VARHDRSZ);
808 MemSet(result, 0, nbytes + VARHDRSZ);
814 for (i = 0; i < ARR_NDIM(v); i++)
816 sprintf(p, "[%d:%d]", lb[i], dimv[i] + lb[i] - 1);
819 VARSIZE(result) = strlen(VARDATA(result)) + VARHDRSZ;
821 PG_RETURN_TEXT_P(result);
824 /*---------------------------------------------------------------------------
826 * This routine takes an array pointer and an index array and returns
827 * a pointer to the referred element if element is passed by
828 * reference otherwise returns the value of the referred element.
829 *---------------------------------------------------------------------------
832 array_ref(ArrayType *array,
846 struct varlena *v = NULL;
850 if (array == (ArrayType *) NULL)
856 * fixed length arrays -- these are assumed to be 1-d
858 if (indx[0] * elmlen > arraylen)
859 elog(ERROR, "array_ref: array bound exceeded");
860 retval = (char *) array + indx[0] * elmlen;
861 return _ArrayCast(retval, elmbyval, elmlen);
863 dim = ARR_DIMS(array);
864 lb = ARR_LBOUND(array);
865 ndim = ARR_NDIM(array);
866 nbytes = (*(int32 *) array) - ARR_OVERHEAD(ndim);
868 if (!SanityCheckInput(ndim, nSubscripts, dim, lb, indx))
871 offset = GetOffset(nSubscripts, dim, lb, indx);
873 if (ARR_IS_LO(array))
878 /* We are assuming fixed element lengths here */
880 lo_name = (char *) ARR_DATA_PTR(array);
882 if ((fd = LOopen(lo_name, ARR_IS_INV(array) ? INV_READ : O_RDONLY)) < 0)
885 if (ARR_IS_CHUNKED(array))
886 v = _ReadChunkArray1El(indx, elmlen, fd, array, isNull);
889 if (DatumGetInt32(DirectFunctionCall3(lo_lseek,
891 Int32GetDatum(offset),
892 Int32GetDatum(SEEK_SET))) < 0)
895 v = (struct varlena *)
896 DatumGetPointer(DirectFunctionCall2(loread,
898 Int32GetDatum(elmlen)));
903 if (VARSIZE(v) - VARHDRSZ < elmlen)
905 DirectFunctionCall1(lo_close, Int32GetDatum(fd));
906 result = _ArrayCast((char *) VARDATA(v), elmbyval, elmlen);
909 char *tempdata = palloc(elmlen);
911 memmove(tempdata, DatumGetPointer(result), elmlen);
912 result = PointerGetDatum(tempdata);
920 offset = offset * elmlen;
921 /* off the end of the array */
922 if (nbytes - offset < 1)
924 retval = ARR_DATA_PTR(array) + offset;
925 return _ArrayCast(retval, elmbyval, elmlen);
931 retval = ARR_DATA_PTR(array);
936 return PointerGetDatum(retval);
937 bytes -= INTALIGN(*(int32 *) retval);
938 retval += INTALIGN(*(int32 *) retval);
945 /*-----------------------------------------------------------------------------
947 * This routine takes an array and a range of indices (upperIndex and
948 * lowerIndx), creates a new array structure for the referred elements
949 * and returns a pointer to it.
950 *-----------------------------------------------------------------------------
953 array_clip(ArrayType *array,
971 if (array == (ArrayType *) NULL)
972 RETURN_NULL(ArrayType *);
973 dim = ARR_DIMS(array);
974 lb = ARR_LBOUND(array);
975 ndim = ARR_NDIM(array);
976 nbytes = (*(int32 *) array) - ARR_OVERHEAD(ndim);
978 if (!SanityCheckInput(ndim, nSubscripts, dim, lb, upperIndx) ||
979 !SanityCheckInput(ndim, nSubscripts, dim, lb, lowerIndx))
980 RETURN_NULL(ArrayType *);
982 for (i = 0; i < nSubscripts; i++)
983 if (lowerIndx[i] > upperIndx[i])
984 elog(ERROR, "lowerIndex cannot be larger than upperIndx");
985 mda_get_range(nSubscripts, span, lowerIndx, upperIndx);
987 if (ARR_IS_LO(array))
993 char *newname = NULL;
1000 elog(ERROR, "array_clip: array of variable length objects not implemented");
1002 lo_name = (char *) ARR_DATA_PTR(array);
1003 if ((fd = LOopen(lo_name, ARR_IS_INV(array) ? INV_READ : O_RDONLY)) < 0)
1004 RETURN_NULL(ArrayType *);
1005 newname = _array_newLO(&newfd, Unix);
1007 bytes = strlen(newname) + 1 + ARR_OVERHEAD(nSubscripts);
1008 newArr = (ArrayType *) palloc(bytes);
1009 memmove(newArr, array, sizeof(ArrayType));
1010 memmove(newArr, &bytes, sizeof(int));
1011 memmove(ARR_DIMS(newArr), span, nSubscripts * sizeof(int));
1012 memmove(ARR_LBOUND(newArr), lowerIndx, nSubscripts * sizeof(int));
1013 strcpy(ARR_DATA_PTR(newArr), newname);
1015 rsize = compute_size(lowerIndx, upperIndx, nSubscripts, elmlen);
1016 if (rsize < MAX_BUFF_SIZE)
1021 buff = palloc(rsize);
1024 if (ARR_IS_CHUNKED(array))
1026 _ReadChunkArray(lowerIndx, upperIndx, elmlen, fd, &(buff[VARHDRSZ]),
1031 _ReadArray(lowerIndx, upperIndx, elmlen, fd, (int) &(buff[VARHDRSZ]),
1035 memmove(buff, &rsize, VARHDRSZ);
1038 bytes = DatumGetInt32(DirectFunctionCall2(lowrite,
1039 Int32GetDatum(newfd),
1040 PointerGetDatum(buff)));
1046 if (ARR_IS_CHUNKED(array))
1048 _ReadChunkArray(lowerIndx, upperIndx, elmlen, fd, (char *) newfd, array,
1052 _ReadArray(lowerIndx, upperIndx, elmlen, fd, newfd, array, 1, isNull);
1069 bytes = getNitems(nSubscripts, span);
1070 bytes = bytes * elmlen + ARR_OVERHEAD(nSubscripts);
1074 bytes = _ArrayClipCount(lowerIndx, upperIndx, array);
1075 bytes += ARR_OVERHEAD(nSubscripts);
1077 newArr = (ArrayType *) palloc(bytes);
1078 memmove(newArr, array, sizeof(ArrayType));
1079 memmove(newArr, &bytes, sizeof(int));
1080 memmove(ARR_DIMS(newArr), span, nSubscripts * sizeof(int));
1081 memmove(ARR_LBOUND(newArr), lowerIndx, nSubscripts * sizeof(int));
1082 _ArrayRange(lowerIndx, upperIndx, elmlen, ARR_DATA_PTR(newArr), array, 1);
1086 /*-----------------------------------------------------------------------------
1088 * This routine sets the value of an array location (specified by
1089 * an index array) to a new value specified by "dataValue".
1091 * returns a pointer to the modified array.
1092 *-----------------------------------------------------------------------------
1095 array_set(ArrayType *array,
1111 if (array == (ArrayType *) NULL)
1112 RETURN_NULL(ArrayType *);
1117 * fixed length arrays -- these are assumed to be 1-d
1119 if (indx[0] * elmlen > arraylen)
1120 elog(ERROR, "array_ref: array bound exceeded");
1121 pos = (char *) array + indx[0] * elmlen;
1122 ArrayCastAndSet(dataValue, elmbyval, elmlen, pos);
1125 dim = ARR_DIMS(array);
1126 lb = ARR_LBOUND(array);
1127 ndim = ARR_NDIM(array);
1128 nbytes = (*(int32 *) array) - ARR_OVERHEAD(ndim);
1130 if (!SanityCheckInput(ndim, nSubscripts, dim, lb, indx))
1132 elog(ERROR, "array_set: array bound exceeded");
1135 offset = GetOffset(nSubscripts, dim, lb, indx);
1137 if (ARR_IS_LO(array))
1142 /* We are assuming fixed element lengths here */
1147 lo_name = ARR_DATA_PTR(array);
1148 if ((fd = LOopen(lo_name, ARR_IS_INV(array) ? INV_WRITE : O_WRONLY)) < 0)
1151 if (DatumGetInt32(DirectFunctionCall3(lo_lseek,
1153 Int32GetDatum(offset),
1154 Int32GetDatum(SEEK_SET))) < 0)
1156 v = (struct varlena *) palloc(elmlen + VARHDRSZ);
1157 VARSIZE(v) = elmlen + VARHDRSZ;
1158 ArrayCastAndSet(dataValue, elmbyval, elmlen, VARDATA(v));
1160 if (DatumGetInt32(DirectFunctionCall2(lowrite,
1162 PointerGetDatum(v)))
1164 RETURN_NULL(ArrayType *);
1167 DirectFunctionCall1(lo_close, Int32GetDatum(fd));
1172 offset = offset * elmlen;
1173 /* off the end of the array */
1174 if (nbytes - offset < 1)
1176 pos = ARR_DATA_PTR(array) + offset;
1180 ArrayType *newarray;
1190 elt_ptr = array_seek(ARR_DATA_PTR(array), -1, offset);
1191 oldlen = INTALIGN(*(int32 *) elt_ptr);
1192 newlen = INTALIGN(*(int32 *) DatumGetPointer(dataValue));
1194 if (oldlen == newlen)
1196 /* new element with same size, overwrite old data */
1197 ArrayCastAndSet(dataValue, elmbyval, elmlen, elt_ptr);
1201 /* new element with different size, reallocate the array */
1202 oldsize = array->size;
1203 lth0 = ARR_OVERHEAD(nSubscripts);
1204 lth1 = (int) (elt_ptr - ARR_DATA_PTR(array));
1205 lth2 = (int) (oldsize - lth0 - lth1 - oldlen);
1206 newsize = lth0 + lth1 + newlen + lth2;
1208 newarray = (ArrayType *) palloc(newsize);
1209 memmove((char *) newarray, (char *) array, lth0 + lth1);
1210 newarray->size = newsize;
1211 newlen = ArrayCastAndSet(dataValue, elmbyval, elmlen,
1212 (char *) newarray + lth0 + lth1);
1213 memmove((char *) newarray + lth0 + lth1 + newlen,
1214 (char *) array + lth0 + lth1 + oldlen, lth2);
1216 /* ??? who should free this storage ??? */
1219 ArrayCastAndSet(dataValue, elmbyval, elmlen, pos);
1223 /*----------------------------------------------------------------------------
1225 * This routine sets the value of a range of array locations (specified
1226 * by upper and lower index values ) to new values passed as
1229 * returns a pointer to the modified array.
1230 *----------------------------------------------------------------------------
1233 array_assgn(ArrayType *array,
1247 if (array == (ArrayType *) NULL)
1248 RETURN_NULL(ArrayType *);
1250 elog(ERROR, "array_assgn: updates on arrays of variable length elements not implemented");
1252 dim = ARR_DIMS(array);
1253 lb = ARR_LBOUND(array);
1254 ndim = ARR_NDIM(array);
1256 if (!SanityCheckInput(ndim, nSubscripts, dim, lb, upperIndx) ||
1257 !SanityCheckInput(ndim, nSubscripts, dim, lb, lowerIndx))
1258 RETURN_NULL(ArrayType *);
1260 for (i = 0; i < nSubscripts; i++)
1261 if (lowerIndx[i] > upperIndx[i])
1262 elog(ERROR, "lowerIndex larger than upperIndx");
1264 if (ARR_IS_LO(array))
1272 lo_name = (char *) ARR_DATA_PTR(array);
1273 if ((fd = LOopen(lo_name, ARR_IS_INV(array) ? INV_WRITE : O_WRONLY)) < 0)
1276 if (ARR_IS_LO(newArr))
1279 lo_name = (char *) ARR_DATA_PTR(newArr);
1280 if ((newfd = LOopen(lo_name, ARR_IS_INV(newArr) ? INV_READ : O_RDONLY)) < 0)
1283 _LOArrayRange(lowerIndx, upperIndx, elmlen, fd, newfd, array, 1, isNull);
1284 DirectFunctionCall1(lo_close, Int32GetDatum(newfd));
1288 _LOArrayRange(lowerIndx, upperIndx, elmlen, fd, (int) ARR_DATA_PTR(newArr),
1291 DirectFunctionCall1(lo_close, Int32GetDatum(fd));
1294 _ArrayRange(lowerIndx, upperIndx, elmlen, ARR_DATA_PTR(newArr), array, 0);
1301 * Map an array through an arbitrary function. Return a new array with
1302 * same dimensions and each source element transformed by fn(). Each
1303 * source element is passed as the first argument to fn(); additional
1304 * arguments to be passed to fn() can be specified by the caller.
1305 * The output array can have a different element type than the input.
1308 * * fcinfo: a function-call data structure pre-constructed by the caller
1309 * to be ready to call the desired function, with everything except the
1310 * first argument position filled in. In particular, flinfo identifies
1311 * the function fn(), and if nargs > 1 then argument positions after the
1312 * first must be preset to the additional values to be passed. The
1313 * first argument position initially holds the input array value.
1314 * * inpType: OID of element type of input array. This must be the same as,
1315 * or binary-compatible with, the first argument type of fn().
1316 * * retType: OID of element type of output array. This must be the same as,
1317 * or binary-compatible with, the result type of fn().
1319 * NB: caller must assure that input array is not NULL. Currently,
1320 * any additional parameters passed to fn() may not be specified as NULL
1324 array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType)
1346 /* Get input array */
1347 if (fcinfo->nargs < 1)
1348 elog(ERROR, "array_map: invalid nargs: %d", fcinfo->nargs);
1349 if (PG_ARGISNULL(0))
1350 elog(ERROR, "array_map: null input array");
1351 v = (ArrayType *) PG_GETARG_VARLENA_P(0);
1353 /* Large objects not yet supported */
1354 if (ARR_IS_LO(v) == true)
1355 elog(ERROR, "array_map: large objects not supported");
1359 nitems = getNitems(ndim, dim);
1361 /* Check for empty array */
1363 PG_RETURN_POINTER(v);
1365 /* Lookup source and result types. Unneeded variables are reused. */
1366 system_cache_lookup(inpType, false, &inp_typlen, &inp_typbyval,
1367 &typdelim, &typelem, &proc, &typalign);
1368 system_cache_lookup(retType, false, &typlen, &typbyval,
1369 &typdelim, &typelem, &proc, &typalign);
1371 /* Allocate temporary array for new values */
1372 values = (char **) palloc(nitems * sizeof(char *));
1373 MemSet(values, 0, nitems * sizeof(char *));
1375 /* Loop over source data */
1376 s = (char *) ARR_DATA_PTR(v);
1377 for (i = 0; i < nitems; i++)
1379 /* Get source element */
1385 elt = (char *) ((int) (*(char *) s));
1388 elt = (char *) ((int) (*(int16 *) s));
1393 elt = (char *) (*(int32 *) s);
1404 s += INTALIGN(*(int32 *) s);
1408 * Apply the given function to source elt and extra args.
1410 * We assume the extra args are non-NULL, so need not check
1411 * whether fn() is strict. Would need to do more work here
1412 * to support arrays containing nulls, too.
1414 fcinfo->arg[0] = (Datum) elt;
1415 fcinfo->argnull[0] = false;
1416 fcinfo->isnull = false;
1417 p = (char *) FunctionCallInvoke(fcinfo);
1419 elog(ERROR, "array_map: cannot handle NULL in array");
1421 /* Update values and total result size */
1431 len = ((typlen > 0) ? typlen : INTALIGN(*(int32 *) p));
1432 /* Needed because _CopyArrayEls tries to pfree items */
1435 p = (char *) palloc(len);
1436 memcpy(p, elt, len);
1443 /* Allocate and initialize the result array */
1444 nbytes += ARR_OVERHEAD(ndim);
1445 result = (ArrayType *) palloc(nbytes);
1446 MemSet(result, 0, nbytes);
1448 memcpy((char *) result, (char *) &nbytes, sizeof(int));
1449 memcpy((char *) ARR_NDIM_PTR(result), (char *) &ndim, sizeof(int));
1450 memcpy((char *) ARR_DIMS(result), ARR_DIMS(v), 2 * ndim * sizeof(int));
1452 /* Copy new values into the result array. values is pfreed. */
1453 _CopyArrayEls((char **) values,
1454 ARR_DATA_PTR(result), nitems,
1455 typlen, typalign, typbyval);
1457 PG_RETURN_POINTER(result);
1460 /*-----------------------------------------------------------------------------
1462 * compares two arrays for equality
1464 * returns true if the arrays are equal, false otherwise.
1465 *-----------------------------------------------------------------------------
1468 array_eq(PG_FUNCTION_ARGS)
1470 ArrayType *array1 = (ArrayType *) PG_GETARG_VARLENA_P(0);
1471 ArrayType *array2 = (ArrayType *) PG_GETARG_VARLENA_P(1);
1473 if (*(int32 *) array1 != *(int32 *) array2)
1474 PG_RETURN_BOOL(false);
1475 if (memcmp(array1, array2, *(int32 *) array1) != 0)
1476 PG_RETURN_BOOL(false);
1477 PG_RETURN_BOOL(true);
1480 /***************************************************************************/
1481 /******************| Support Routines |*****************/
1482 /***************************************************************************/
1484 system_cache_lookup(Oid element_type,
1493 HeapTuple typeTuple;
1494 Form_pg_type typeStruct;
1496 typeTuple = SearchSysCacheTuple(TYPEOID,
1497 ObjectIdGetDatum(element_type),
1500 if (!HeapTupleIsValid(typeTuple))
1502 elog(ERROR, "array_out: Cache lookup failed for type %u\n",
1506 typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
1507 *typlen = typeStruct->typlen;
1508 *typbyval = typeStruct->typbyval;
1509 *typdelim = typeStruct->typdelim;
1510 *typelem = typeStruct->typelem;
1511 *typalign = typeStruct->typalign;
1513 *proc = typeStruct->typinput;
1515 *proc = typeStruct->typoutput;
1519 _ArrayCast(char *value, bool byval, int len)
1526 return (Datum) *value;
1528 return (Datum) *(int16 *) value;
1531 return (Datum) *(int32 *) value;
1533 elog(ERROR, "array_ref: byval and elt len > 4!");
1538 return (Datum) value;
1544 ArrayCastAndSet(Datum src,
1558 *dest = DatumGetChar(src);
1561 *(int16 *) dest = DatumGetInt16(src);
1564 *(int32 *) dest = DatumGetInt32(src);
1569 memmove(dest, DatumGetPointer(src), typlen);
1574 memmove(dest, DatumGetPointer(src), *(int32 *) DatumGetPointer(src));
1575 inc = (INTALIGN(*(int32 *) DatumGetPointer(src)));
1582 _AdvanceBy1word(char *str, char **word)
1590 while (isspace(*str))
1593 if ((space = (char *) strchr(str, ' ')) != (char *) NULL)
1606 SanityCheckInput(int ndim, int n, int *dim, int *lb, int *indx)
1610 /* Do Sanity check on input */
1613 for (i = 0; i < ndim; i++)
1614 if ((lb[i] > indx[i]) || (indx[i] >= (dim[i] + lb[i])))
1620 _ArrayRange(int *st,
1640 n = ARR_NDIM(array);
1641 dim = ARR_DIMS(array);
1642 lb = ARR_LBOUND(array);
1643 srcPtr = ARR_DATA_PTR(array);
1644 for (i = 0; i < n; st[i] -= lb[i], endp[i] -= lb[i], i++);
1645 mda_get_prod(n, dim, prod);
1646 st_pos = tuple2linear(n, st, prod);
1647 srcPtr = array_seek(srcPtr, bsize, st_pos);
1648 mda_get_range(n, span, st, endp);
1649 mda_get_offset_values(n, dist, prod, span);
1650 for (i = 0; i < n; indx[i++] = 0);
1655 srcPtr = array_seek(srcPtr, bsize, dist[j]);
1657 inc = array_read(destPtr, bsize, 1, srcPtr);
1659 inc = array_read(srcPtr, bsize, 1, destPtr);
1662 } while ((j = next_tuple(i + 1, indx, span)) != -1);
1666 _ArrayClipCount(int *stI, int *endpI, ArrayType *array)
1684 n = ARR_NDIM(array);
1685 dim = ARR_DIMS(array);
1686 lb = ARR_LBOUND(array);
1687 ptr = ARR_DATA_PTR(array);
1688 for (i = 0; i < n; st[i] = stI[i] - lb[i], endp[i] = endpI[i] - lb[i], i++);
1689 mda_get_prod(n, dim, prod);
1690 st_pos = tuple2linear(n, st, prod);
1691 ptr = array_seek(ptr, -1, st_pos);
1692 mda_get_range(n, span, st, endp);
1693 mda_get_offset_values(n, dist, prod, span);
1694 for (i = 0; i < n; indx[i++] = 0);
1698 ptr = array_seek(ptr, -1, dist[j]);
1699 inc = INTALIGN(*(int32 *) ptr);
1702 } while ((j = next_tuple(i + 1, indx, span)) != -1);
1707 array_seek(char *ptr, int eltsize, int nitems)
1712 return ptr + eltsize * nitems;
1713 for (i = 0; i < nitems; i++)
1714 ptr += INTALIGN(*(int32 *) ptr);
1719 array_read(char *destptr, int eltsize, int nitems, char *srcptr)
1727 memmove(destptr, srcptr, eltsize * nitems);
1728 return eltsize * nitems;
1730 for (i = inc = 0; i < nitems; i++)
1732 tmp = (INTALIGN(*(int32 *) srcptr));
1733 memmove(destptr, srcptr, tmp);
1742 _LOArrayRange(int *st,
1765 n = ARR_NDIM(array);
1766 dim = ARR_DIMS(array);
1767 lb = ARR_LBOUND(array);
1768 for (i = 0; i < n; st[i] -= lb[i], endp[i] -= lb[i], i++);
1770 mda_get_prod(n, dim, prod);
1771 st_pos = tuple2linear(n, st, prod);
1772 offset = st_pos * bsize;
1773 if (DatumGetInt32(DirectFunctionCall3(lo_lseek,
1774 Int32GetDatum(srcfd),
1775 Int32GetDatum(offset),
1776 Int32GetDatum(SEEK_SET))) < 0)
1778 mda_get_range(n, span, st, endp);
1779 mda_get_offset_values(n, dist, prod, span);
1780 for (i = 0; i < n; indx[i++] = 0);
1781 for (i = n - 1, inc = bsize; i >= 0; inc *= span[i--])
1787 offset += (dist[j] * bsize);
1788 if (DatumGetInt32(DirectFunctionCall3(lo_lseek,
1789 Int32GetDatum(srcfd),
1790 Int32GetDatum(offset),
1791 Int32GetDatum(SEEK_SET))) < 0)
1793 tmp = _LOtransfer((char **) &srcfd, inc, 1, (char **) &destfd, isSrcLO, 1);
1797 } while ((j = next_tuple(i + 1, indx, span)) != -1);
1825 n = ARR_NDIM(array);
1826 dim = ARR_DIMS(array);
1827 lb = ARR_LBOUND(array);
1828 for (i = 0; i < n; st[i] -= lb[i], endp[i] -= lb[i], i++);
1830 mda_get_prod(n, dim, prod);
1831 st_pos = tuple2linear(n, st, prod);
1832 offset = st_pos * bsize;
1833 if (DatumGetInt32(DirectFunctionCall3(lo_lseek,
1834 Int32GetDatum(srcfd),
1835 Int32GetDatum(offset),
1836 Int32GetDatum(SEEK_SET))) < 0)
1838 mda_get_range(n, span, st, endp);
1839 mda_get_offset_values(n, dist, prod, span);
1840 for (i = 0; i < n; indx[i++] = 0);
1841 for (i = n - 1, inc = bsize; i >= 0; inc *= span[i--])
1847 offset += (dist[j] * bsize);
1848 if (DatumGetInt32(DirectFunctionCall3(lo_lseek,
1849 Int32GetDatum(srcfd),
1850 Int32GetDatum(offset),
1851 Int32GetDatum(SEEK_SET))) < 0)
1853 tmp = _LOtransfer((char **) &destfd, inc, 1, (char **) &srcfd, 1, isDestLO);
1857 } while ((j = next_tuple(i + 1, indx, span)) != -1);
1862 _LOtransfer(char **destfd,
1869 #define MAX_READ (512 * 1024)
1871 #define min(a, b) (a < b ? a : b)
1873 struct varlena *v = NULL;
1878 inc = nitems * size;
1879 if (isSrcLO && isDestLO && inc > 0)
1880 for (tmp = 0, resid = inc;
1881 resid > 0 && (inc = min(resid, MAX_READ)) > 0; resid -= inc)
1884 v = (struct varlena *)
1885 DatumGetPointer(DirectFunctionCall2(loread,
1886 Int32GetDatum((int32) *srcfd),
1887 Int32GetDatum(inc)));
1888 if (VARSIZE(v) - VARHDRSZ < inc)
1893 tmp += DatumGetInt32(DirectFunctionCall2(lowrite,
1894 Int32GetDatum((int32) *destfd),
1895 PointerGetDatum(v)));
1900 else if (!isSrcLO && isDestLO)
1902 tmp = lo_write((int) *destfd, *srcfd, inc);
1903 *srcfd = *srcfd + tmp;
1905 else if (isSrcLO && !isDestLO)
1907 tmp = lo_read((int) *srcfd, *destfd, inc);
1908 *destfd = *destfd + tmp;
1912 memmove(*destfd, *srcfd, inc);
1922 _array_newLO(int *fd, int flag)
1925 char saveName[NAME_LEN];
1927 p = (char *) palloc(NAME_LEN);
1928 sprintf(p, "/Arry.%u", newoid());
1929 strcpy(saveName, p);
1931 if ((*fd = LOcreat(saveName, 0600, flag)) < 0)
1932 elog(ERROR, "Large object create failed");