aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/arrayfuncs.c
diff options
context:
space:
mode:
authorMarc G. Fournier <scrappy@hub.org>1996-07-09 06:22:35 +0000
committerMarc G. Fournier <scrappy@hub.org>1996-07-09 06:22:35 +0000
commitd31084e9d1118b25fd16580d9d8c2924b5740dff (patch)
tree3179e66307d54df9c7b966543550e601eb55e668 /src/backend/utils/adt/arrayfuncs.c
downloadpostgresql-d31084e9d1118b25fd16580d9d8c2924b5740dff.tar.gz
postgresql-d31084e9d1118b25fd16580d9d8c2924b5740dff.zip
Postgres95 1.01 Distribution - Virgin SourcesPG95-1_01
Diffstat (limited to 'src/backend/utils/adt/arrayfuncs.c')
-rw-r--r--src/backend/utils/adt/arrayfuncs.c1375
1 files changed, 1375 insertions, 0 deletions
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c
new file mode 100644
index 00000000000..2e780fb03b6
--- /dev/null
+++ b/src/backend/utils/adt/arrayfuncs.c
@@ -0,0 +1,1375 @@
+/*-------------------------------------------------------------------------
+ *
+ * arrayfuncs.c--
+ * Special functions for arrays.
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.1.1.1 1996/07/09 06:22:03 scrappy Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include <ctype.h>
+#include <stdio.h>
+
+#include "postgres.h"
+
+#include "catalog/catalog.h"
+#include "catalog/pg_type.h"
+
+#include "utils/syscache.h"
+#include "utils/palloc.h"
+#include "utils/memutils.h"
+#include "storage/fd.h" /* for SEEK_ */
+#include "fmgr.h"
+#include "utils/elog.h"
+#include "utils/array.h"
+
+#include "libpq/libpq-fs.h"
+#include "libpq/be-fsstubs.h"
+
+#define ASSGN "="
+
+/* An array has the following internal structure:
+ * <nbytes> - total number of bytes
+ * <ndim> - number of dimensions of the array
+ * <flags> - bit mask of flags
+ * <dim> - size of each array axis
+ * <dim_lower> - lower boundary of each dimension
+ * <actual data> - whatever is the stored data
+*/
+
+/*-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-*/
+static int _ArrayCount(char *str, int dim[], int typdelim);
+static char *_ReadArrayStr(char *arrayStr, int nitems, int ndim, int dim[],
+ func_ptr inputproc, Oid typelem, char typdelim,
+ int typlen, bool typbyval, char typalign,
+ int *nbytes);
+static char *_ReadLOArray(char *str, int *nbytes, int *fd, bool *chunkFlag,
+ int ndim, int dim[], int baseSize);
+static void _CopyArrayEls(char **values, char *p, int nitems, int typlen,
+ char typalign, bool typbyval);
+static void system_cache_lookup(Oid element_type, bool input, int *typlen,
+ bool *typbyval, char *typdelim, Oid *typelem, Oid *proc,
+ char *typalign);
+static Datum _ArrayCast(char *value, bool byval, int len);
+static char *_AdvanceBy1word(char *str, char **word);
+static void _ArrayRange(int st[], int endp[], int bsize, char *destPtr,
+ ArrayType *array, int from);
+static int _ArrayClipCount(int stI[], int endpI[], ArrayType *array);
+static void _LOArrayRange(int st[], int endp[], int bsize, int srcfd,
+ int destfd, ArrayType *array, int isSrcLO, bool *isNull);
+static void _ReadArray (int st[], int endp[], int bsize, int srcfd, int destfd,
+ ArrayType *array, int isDestLO, bool *isNull);
+static char *_array_set(ArrayType *array, struct varlena *indx_str,
+ struct varlena *dataPtr);
+static ArrayCastAndSet(char *src, bool typbyval, int typlen, char *dest);
+
+
+/*---------------------------------------------------------------------
+ * array_in :
+ * converts an array from the external format in "string" to
+ * it internal format.
+ * return value :
+ * the internal representation of the input array
+ *--------------------------------------------------------------------
+ */
+char *
+array_in(char *string, /* input array in external form */
+ Oid element_type) /* type OID of an array element */
+{
+ int typlen;
+ bool typbyval, done;
+ char typdelim;
+ Oid typinput;
+ Oid typelem;
+ char *string_save, *p, *q, *r;
+ func_ptr inputproc;
+ int i, nitems, dummy;
+ int32 nbytes;
+ char *dataPtr;
+ ArrayType *retval;
+ int ndim, dim[MAXDIM], lBound[MAXDIM];
+ char typalign;
+
+ system_cache_lookup(element_type, true, &typlen, &typbyval, &typdelim,
+ &typelem, &typinput, &typalign);
+
+ fmgr_info(typinput, &inputproc, &dummy);
+
+ string_save = (char *) palloc(strlen(string) + 3);
+ strcpy(string_save, string);
+
+ /* --- read array dimensions ---------- */
+ p = q = string_save; done = false;
+ for ( ndim = 0; !done; ) {
+ while (isspace(*p)) p++;
+ if (*p == '[' ) {
+ p++;
+ if ((r = (char *)strchr(p, ':')) == (char *)NULL)
+ lBound[ndim] = 1;
+ else {
+ *r = '\0';
+ lBound[ndim] = atoi(p);
+ p = r + 1;
+ }
+ for (q = p; isdigit(*q); q++);
+ if (*q != ']')
+ elog(WARN, "array_in: missing ']' in array declaration");
+ *q = '\0';
+ dim[ndim] = atoi(p);
+ if ((dim[ndim] < 0) || (lBound[ndim] < 0))
+ elog(WARN,"array_in: array dimensions need to be positive");
+ dim[ndim] = dim[ndim] - lBound[ndim] + 1;
+ if (dim[ndim] < 0)
+ elog(WARN, "array_in: upper_bound cannot be < lower_bound");
+ p = q + 1; ndim++;
+ } else {
+ done = true;
+ }
+ }
+
+ if (ndim == 0) {
+ if (*p == '{') {
+ ndim = _ArrayCount(p, dim, typdelim);
+ for (i = 0; i < ndim; lBound[i++] = 1);
+ } else {
+ elog(WARN,"array_in: Need to specify dimension");
+ }
+ } else {
+ while (isspace(*p)) p++;
+ if (strncmp(p, ASSGN, strlen(ASSGN)))
+ elog(WARN, "array_in: missing assignment operator");
+ p+= strlen(ASSGN);
+ while (isspace(*p)) p++;
+ }
+
+ nitems = getNitems( ndim, dim);
+ if (nitems == 0) {
+ char *emptyArray = palloc(sizeof(ArrayType));
+ memset(emptyArray, 0, sizeof(ArrayType));
+ * (int32 *) emptyArray = sizeof(ArrayType);
+ return emptyArray;
+ }
+
+ if (*p == '{') {
+ /* array not a large object */
+ dataPtr =
+ (char *) _ReadArrayStr(p, nitems, ndim, dim, inputproc, typelem,
+ typdelim, typlen, typbyval, typalign,
+ &nbytes );
+ nbytes += ARR_OVERHEAD(ndim);
+ retval = (ArrayType *) palloc(nbytes);
+ memset(retval,0, nbytes);
+ memmove(retval, (char *)&nbytes, sizeof(int));
+ memmove((char*)ARR_NDIM_PTR(retval), (char *)&ndim, sizeof(int));
+ SET_LO_FLAG (false, retval);
+ memmove((char *)ARR_DIMS(retval), (char *)dim, ndim*sizeof(int));
+ memmove((char *)ARR_LBOUND(retval), (char *)lBound,
+ ndim*sizeof(int));
+ /* dataPtr is an array of arbitraystuff even though its type is char*
+ cast to char** to pass to _CopyArrayEls for now - jolly */
+ _CopyArrayEls((char**)dataPtr,
+ ARR_DATA_PTR(retval), nitems,
+ typlen, typalign, typbyval);
+ } else {
+#ifdef LOARRAY
+ int dummy, bytes;
+ bool chunked = false;
+
+ dataPtr = _ReadLOArray(p, &bytes, &dummy, &chunked, ndim,
+ dim, typlen );
+ nbytes = bytes + ARR_OVERHEAD(ndim);
+ retval = (ArrayType *) palloc(nbytes);
+ memset(retval, 0,nbytes);
+ memmove(retval, (char *)&nbytes, sizeof(int));
+ memmove((char *)ARR_NDIM_PTR(retval), (char *)&ndim, sizeof(int));
+ SET_LO_FLAG (true, retval);
+ SET_CHUNK_FLAG (chunked, retval);
+ memmove((char *)ARR_DIMS(retval), (char *)dim, ndim*sizeof(int));
+ memmove((char *)ARR_LBOUND(retval),(char *)lBound, ndim*sizeof(int));
+ memmove(ARR_DATA_PTR(retval), dataPtr, bytes);
+#endif
+ elog(WARN, "large object arrays not supported");
+ }
+ pfree(string_save);
+ return((char *)retval);
+}
+
+/*-----------------------------------------------------------------------------
+ * _ArrayCount --
+ * Counts the number of dimensions and the dim[] array for an array string.
+ * The syntax for array input is C-like nested curly braces
+ *-----------------------------------------------------------------------------
+ */
+static int
+_ArrayCount(char *str, int dim[], int typdelim)
+{
+ int nest_level = 0, i;
+ int ndim = 0, temp[MAXDIM];
+ bool scanning_string = false;
+ bool eoArray = false;
+ char *q;
+
+ for (i = 0; i < MAXDIM; ++i) {
+ temp[i] = dim[i] = 0;
+ }
+
+ if (strncmp (str, "{}", 2) == 0) return(0);
+
+ q = str;
+ while (eoArray != true) {
+ bool done = false;
+ while (!done) {
+ switch (*q) {
+ case '\"':
+ scanning_string = ! scanning_string;
+ break;
+ case '{':
+ if (!scanning_string) {
+ temp[nest_level] = 0;
+ nest_level++;
+ }
+ break;
+ case '}':
+ if (!scanning_string) {
+ if (!ndim) ndim = nest_level;
+ nest_level--;
+ if (nest_level) temp[nest_level-1]++;
+ if (nest_level == 0) eoArray = done = true;
+ }
+ break;
+ default:
+ if (!ndim) ndim = nest_level;
+ if (*q == typdelim && !scanning_string )
+ done = true;
+ break;
+ }
+ if (!done) q++;
+ }
+ temp[ndim-1]++;
+ q++;
+ if (!eoArray)
+ while (isspace(*q)) q++;
+ }
+ for (i = 0; i < ndim; ++i) {
+ dim[i] = temp[i];
+ }
+
+ return(ndim);
+}
+
+/*---------------------------------------------------------------------------
+ * _ReadArrayStr :
+ * parses the array string pointed by "arrayStr" and converts it in the
+ * internal format. The external format expected is like C array
+ * declaration. Unspecified elements are initialized to zero for fixed length
+ * base types and to empty varlena structures for variable length base
+ * types.
+ * result :
+ * returns the internal representation of the array elements
+ * nbytes is set to the size of the array in its internal representation.
+ *---------------------------------------------------------------------------
+ */
+static char *
+_ReadArrayStr(char *arrayStr,
+ int nitems,
+ int ndim,
+ int dim[],
+ func_ptr inputproc, /* function used for the conversion */
+ Oid typelem,
+ char typdelim,
+ int typlen,
+ bool typbyval,
+ char typalign,
+ int *nbytes)
+{
+ int i, nest_level = 0;
+ char *p, *q, *r, **values;
+ bool scanning_string = false;
+ int indx[MAXDIM], prod[MAXDIM];
+ bool eoArray = false;
+
+ mda_get_prod(ndim, dim, prod);
+ for (i = 0; i < ndim; indx[i++] = 0);
+ /* read array enclosed within {} */
+ values = (char **) palloc(nitems * sizeof(char *));
+ memset(values, 0, nitems * sizeof(char *));
+ q = p = arrayStr;
+
+ while ( ! eoArray ) {
+ bool done = false;
+ int i = -1;
+
+ while (!done) {
+ switch (*q) {
+ case '\\':
+ /* Crunch the string on top of the backslash. */
+ for (r = q; *r != '\0'; r++) *r = *(r+1);
+ break;
+ case '\"':
+ if (!scanning_string ) {
+ while (p != q) p++;
+ p++; /* get p past first doublequote */
+ } else
+ *q = '\0';
+ scanning_string = ! scanning_string;
+ break;
+ case '{':
+ if (!scanning_string) {
+ p++;
+ nest_level++;
+ if (nest_level > ndim)
+ elog(WARN, "array_in: illformed array constant");
+ indx[nest_level - 1] = 0;
+ indx[ndim - 1] = 0;
+ }
+ break;
+ case '}':
+ if (!scanning_string) {
+ if (i == -1)
+ i = tuple2linear(ndim, indx, prod);
+ nest_level--;
+ if (nest_level == 0)
+ eoArray = done = true;
+ else {
+ *q = '\0';
+ indx[nest_level - 1]++;
+ }
+ }
+ break;
+ default:
+ if (*q == typdelim && !scanning_string ) {
+ if (i == -1)
+ i = tuple2linear(ndim, indx, prod);
+ done = true;
+ indx[ndim - 1]++;
+ }
+ break;
+ }
+ if (!done)
+ q++;
+ }
+ *q = '\0';
+ if (i >= nitems)
+ elog(WARN, "array_in: illformed array constant");
+ values[i] = (*inputproc) (p, typelem);
+ p = ++q;
+ if (!eoArray)
+ /*
+ * if not at the end of the array skip white space
+ */
+ while (isspace(*q)) {
+ p++;
+ q++;
+ }
+ }
+ if (typlen > 0) {
+ *nbytes = nitems * typlen;
+ if (!typbyval)
+ for (i = 0; i < nitems; i++)
+ if (!values[i]) {
+ values[i] = palloc(typlen);
+ memset(values[i], 0, typlen);
+ }
+ } else {
+ for (i = 0, *nbytes = 0; i < nitems; i++) {
+ if (values[i]) {
+ if (typalign=='d') {
+ *nbytes += DOUBLEALIGN(* (int32 *) values[i]);
+ } else {
+ *nbytes += INTALIGN(* (int32 *) values[i]);
+ }
+ } else {
+ *nbytes += sizeof(int32);
+ values[i] = palloc(sizeof(int32));
+ *(int32 *)values[i] = sizeof(int32);
+ }
+ }
+ }
+ return((char *)values);
+}
+
+
+/*----------------------------------------------------------------------------
+ * Read data about an array to be stored as a large object
+ *----------------------------------------------------------------------------
+ */
+static char *
+_ReadLOArray(char *str,
+ int *nbytes,
+ int *fd,
+ bool *chunkFlag,
+ int ndim,
+ int dim[],
+ int baseSize)
+{
+ char *inputfile, *accessfile = NULL, *chunkfile = NULL;
+ char *retStr, *_AdvanceBy1word();
+ Oid lobjId;
+
+ str = _AdvanceBy1word(str, &inputfile);
+
+ while (str != NULL) {
+ char *word;
+
+ str = _AdvanceBy1word(str, &word);
+
+ if (!strcmp (word, "-chunk")) {
+ if (str == NULL)
+ elog(WARN, "array_in: access pattern file required");
+ str = _AdvanceBy1word(str, &accessfile);
+ }
+ else if (!strcmp (word, "-noreorg")) {
+ if (str == NULL)
+ elog(WARN, "array_in: chunk file required");
+ str = _AdvanceBy1word(str, &chunkfile);
+ } else {
+ elog(WARN, "usage: <input file> -chunk DEFAULT/<access pattern file> -invert/-native [-noreorg <chunk file>]");
+ }
+ }
+
+ if (inputfile == NULL)
+ elog(WARN, "array_in: missing file name");
+ lobjId = lo_creat(0);
+ *fd = lo_open(lobjId, INV_READ);
+ if ( *fd < 0 )
+ elog(WARN, "Large object create failed");
+ retStr = inputfile;
+ *nbytes = strlen(retStr) + 2;
+
+ if ( accessfile ) {
+ FILE *afd;
+ if ((afd = fopen (accessfile, "r")) == NULL)
+ elog(WARN, "unable to open access pattern file");
+ *chunkFlag = true;
+ retStr = _ChunkArray(*fd, afd, ndim, dim, baseSize, nbytes,
+ chunkfile);
+ }
+ return(retStr);
+}
+
+static void
+_CopyArrayEls(char **values,
+ char *p,
+ int nitems,
+ int typlen,
+ char typalign,
+ bool typbyval)
+{
+ int i;
+
+ for (i = 0; i < nitems; i++) {
+ int inc;
+ inc = ArrayCastAndSet(values[i], typbyval, typlen, p);
+ p += inc;
+ if (!typbyval)
+ pfree(values[i]);
+ }
+ pfree(values);
+}
+
+/*-------------------------------------------------------------------------
+ * array_out :
+ * takes the internal representation of an array and returns a string
+ * containing the array in its external format.
+ *-------------------------------------------------------------------------
+ */
+char *
+array_out(ArrayType *v, Oid element_type)
+{
+ int typlen;
+ bool typbyval;
+ char typdelim;
+ Oid typoutput, typelem;
+ func_ptr outputproc;
+ char typalign;
+
+ char *p, *retval, **values, delim[2];
+ int nitems, overall_length, i, j, k, indx[MAXDIM];
+ bool dummy_bool;
+ int dummy_int;
+ int ndim, *dim;
+
+ if (v == (ArrayType *) NULL)
+ return ((char *) NULL);
+
+ if (ARR_IS_LO(v) == true) {
+ char *p, *save_p;
+ int nbytes;
+
+ /* get a wide string to print to */
+ p = array_dims(v, &dummy_bool);
+ nbytes = strlen(ARR_DATA_PTR(v)) + 4 + *(int *)p;
+
+ save_p = (char *) palloc(nbytes);
+
+ strcpy(save_p, p + sizeof(int));
+ strcat(save_p, ASSGN);
+ strcat(save_p, ARR_DATA_PTR(v));
+ pfree(p);
+ return (save_p);
+ }
+
+ system_cache_lookup(element_type, false, &typlen, &typbyval,
+ &typdelim, &typelem, &typoutput, &typalign);
+ fmgr_info(typoutput, & outputproc, &dummy_int);
+ sprintf(delim, "%c", typdelim);
+ ndim = ARR_NDIM(v);
+ dim = ARR_DIMS(v);
+ nitems = getNitems(ndim, dim);
+
+ if (nitems == 0) {
+ char *emptyArray = palloc(3);
+ emptyArray[0] = '{';
+ emptyArray[1] = '}';
+ emptyArray[2] = '\0';
+ return emptyArray;
+ }
+
+ p = ARR_DATA_PTR(v);
+ overall_length = 1; /* [TRH] don't forget to count \0 at end. */
+ values = (char **) palloc(nitems * sizeof (char *));
+ for (i = 0; i < nitems; i++) {
+ if (typbyval) {
+ switch(typlen) {
+ case 1:
+ values[i] = (*outputproc) (*p, typelem);
+ break;
+ case 2:
+ values[i] = (*outputproc) (* (int16 *) p, typelem);
+ break;
+ case 3:
+ case 4:
+ values[i] = (*outputproc) (* (int32 *) p, typelem);
+ break;
+ }
+ p += typlen;
+ } else {
+ values[i] = (*outputproc) (p, typelem);
+ if (typlen > 0)
+ p += typlen;
+ else
+ p += INTALIGN(* (int32 *) p);
+ /*
+ * For the pair of double quotes
+ */
+ overall_length += 2;
+ }
+ overall_length += (strlen(values[i]) + 1);
+ }
+
+ /*
+ * count total number of curly braces in output string
+ */
+ for (i = j = 0, k = 1; i < ndim; k *= dim[i++], j += k);
+
+ p = (char *) palloc(overall_length + 2*j);
+ retval = p;
+
+ strcpy(p, "{");
+ for (i = 0; i < ndim; indx[i++] = 0);
+ j = 0; k = 0;
+ do {
+ for (i = j; i < ndim - 1; i++)
+ strcat(p, "{");
+ /*
+ * Surround anything that is not passed by value in double quotes.
+ * See above for more details.
+ */
+ if (!typbyval) {
+ strcat(p, "\"");
+ strcat(p, values[k]);
+ strcat(p, "\"");
+ } else
+ strcat(p, values[k]);
+ pfree(values[k++]);
+
+ for (i = ndim - 1; i >= 0; i--) {
+ indx[i] = (indx[i] + 1)%dim[i];
+ if (indx[i]) {
+ strcat (p, delim);
+ break;
+ } else
+ strcat (p, "}");
+ }
+ j = i;
+ } while (j != -1);
+
+ pfree(values);
+ return(retval);
+}
+
+/*-----------------------------------------------------------------------------
+ * array_dims :
+ * returns the dimension of the array pointed to by "v"
+ *----------------------------------------------------------------------------
+ */
+char *
+array_dims(ArrayType *v, bool *isNull)
+{
+ char *p, *save_p;
+ int nbytes, i;
+ int *dimv, *lb;
+
+ if (v == (ArrayType *) NULL) RETURN_NULL;
+ nbytes = ARR_NDIM(v)*33;
+ /*
+ * 33 since we assume 15 digits per number + ':' +'[]'
+ */
+ save_p = p = (char *) palloc(nbytes + 4);
+ memset(save_p, 0, nbytes + 4);
+ dimv = ARR_DIMS(v); lb = ARR_LBOUND(v);
+ p += 4;
+ for (i = 0; i < ARR_NDIM(v); i++) {
+ sprintf(p, "[%d:%d]", lb[i], dimv[i]+lb[i]-1);
+ p += strlen(p);
+ }
+ nbytes = strlen(save_p + 4) + 4;
+ memmove(save_p, &nbytes,4);
+ return (save_p);
+}
+
+/*---------------------------------------------------------------------------
+ * array_ref :
+ * This routing takes an array pointer and an index array and returns
+ * a pointer to the referred element if element is passed by
+ * reference otherwise returns the value of the referred element.
+ *---------------------------------------------------------------------------
+ */
+Datum
+array_ref(ArrayType *array,
+ int n,
+ int indx[],
+ int reftype,
+ int elmlen,
+ int arraylen,
+ bool *isNull)
+{
+ int i, ndim, *dim, *lb, offset, nbytes;
+ struct varlena *v;
+ char *retval;
+
+ if (array == (ArrayType *) NULL) RETURN_NULL;
+ if (arraylen > 0) {
+ /*
+ * fixed length arrays -- these are assumed to be 1-d
+ */
+ if (indx[0]*elmlen > arraylen)
+ elog(WARN, "array_ref: array bound exceeded");
+ retval = (char *)array + indx[0]*elmlen;
+ return _ArrayCast(retval, reftype, elmlen);
+ }
+ dim = ARR_DIMS(array);
+ lb = ARR_LBOUND(array);
+ ndim = ARR_NDIM(array);
+ nbytes = (* (int32 *) array) - ARR_OVERHEAD(ndim);
+
+ if (!SanityCheckInput(ndim, n, dim, lb, indx))
+ RETURN_NULL;
+
+ offset = GetOffset(n, dim, lb, indx);
+
+ if (ARR_IS_LO(array)) {
+ char * lo_name;
+ int fd;
+
+ /* We are assuming fixed element lengths here */
+ offset *= elmlen;
+ lo_name = (char *)ARR_DATA_PTR(array);
+#ifdef LOARRAY
+ if ((fd = LOopen(lo_name, ARR_IS_INV(array)?INV_READ:O_RDONLY)) < 0)
+ RETURN_NULL;
+#endif
+ if (ARR_IS_CHUNKED(array))
+ v = _ReadChunkArray1El(indx, elmlen, fd, array, isNull);
+ else {
+ if (lo_lseek(fd, offset, SEEK_SET) < 0)
+ RETURN_NULL;
+#ifdef LOARRAY
+ v = (struct varlena *) LOread(fd, elmlen);
+#endif
+ }
+ if (*isNull) RETURN_NULL;
+ if (VARSIZE(v) - 4 < elmlen)
+ RETURN_NULL;
+ (void) lo_close(fd);
+ retval = (char *)_ArrayCast((char *)VARDATA(v), reftype, elmlen);
+ if ( reftype == 0) { /* not by value */
+ char * tempdata = palloc (elmlen);
+ memmove(tempdata, retval, elmlen);
+ retval = tempdata;
+ }
+ pfree(v);
+ return (Datum) retval;
+ }
+
+ if (elmlen > 0) {
+ offset = offset * elmlen;
+ /* off the end of the array */
+ if (nbytes - offset < 1) RETURN_NULL;
+ retval = ARR_DATA_PTR (array) + offset;
+ return _ArrayCast(retval, reftype, elmlen);
+ } else {
+ bool done = false;
+ char *temp;
+ int bytes = nbytes;
+ temp = ARR_DATA_PTR (array);
+ i = 0;
+ while (bytes > 0 && !done) {
+ if (i == offset) {
+ retval = temp;
+ done = true;
+ }
+ bytes -= INTALIGN(* (int32 *) temp);
+ temp += INTALIGN(* (int32 *) temp);
+ i++;
+ }
+ if (! done)
+ RETURN_NULL;
+ return (Datum) retval;
+ }
+}
+
+/*-----------------------------------------------------------------------------
+ * array_clip :
+ * This routine takes an array and a range of indices (upperIndex and
+ * lowerIndx), creates a new array structure for the referred elements
+ * and returns a pointer to it.
+ *-----------------------------------------------------------------------------
+ */
+Datum
+array_clip(ArrayType *array,
+ int n,
+ int upperIndx[],
+ int lowerIndx[],
+ int reftype,
+ int len,
+ bool *isNull)
+{
+ int i, ndim, *dim, *lb, nbytes;
+ ArrayType *newArr;
+ int bytes, span[MAXDIM];
+
+ /* timer_start(); */
+ if (array == (ArrayType *) NULL)
+ RETURN_NULL;
+ dim = ARR_DIMS(array);
+ lb = ARR_LBOUND(array);
+ ndim = ARR_NDIM(array);
+ nbytes = (* (int32 *) array) - ARR_OVERHEAD(ndim);
+
+ if (!SanityCheckInput(ndim, n, dim, lb, upperIndx))
+ RETURN_NULL;
+
+ if (!SanityCheckInput(ndim, n, dim, lb, lowerIndx))
+ RETURN_NULL;
+
+ for (i = 0; i < n; i++)
+ if (lowerIndx[i] > upperIndx[i])
+ elog(WARN, "lowerIndex cannot be larger than upperIndx");
+ mda_get_range(n, span, lowerIndx, upperIndx);
+
+ if (ARR_IS_LO(array)) {
+ char * lo_name, * newname;
+ int fd, newfd, isDestLO = true, rsize;
+
+ if (len < 0)
+ elog(WARN, "array_clip: array of variable length objects not supported");
+#ifdef LOARRAY
+ lo_name = (char *)ARR_DATA_PTR(array);
+ if ((fd = LOopen(lo_name, ARR_IS_INV(array)?INV_READ:O_RDONLY)) < 0)
+ RETURN_NULL;
+ newname = _array_newLO( &newfd, Unix );
+#endif
+ bytes = strlen(newname) + 1 + ARR_OVERHEAD(n);
+ newArr = (ArrayType *) palloc(bytes);
+ memmove(newArr, array, sizeof(ArrayType));
+ memmove(newArr, &bytes, sizeof(int));
+ memmove(ARR_DIMS(newArr), span, n*sizeof(int));
+ memmove(ARR_LBOUND(newArr), lowerIndx, n*sizeof(int));
+ strcpy(ARR_DATA_PTR(newArr), newname);
+
+ rsize = compute_size (lowerIndx, upperIndx, n, len);
+ if (rsize < MAX_BUFF_SIZE) {
+ char *buff;
+ rsize += 4;
+ buff = palloc(rsize);
+ if ( buff )
+ isDestLO = false;
+ if (ARR_IS_CHUNKED(array)) {
+ _ReadChunkArray(lowerIndx, upperIndx, len, fd, &(buff[4]),
+ array,0,isNull);
+ } else {
+ _ReadArray(lowerIndx, upperIndx, len, fd, (int)&(buff[4]),
+ array,
+ 0,isNull);
+ }
+ memmove(buff, &rsize, 4);
+#ifdef LOARRAY
+ if (! *isNull)
+ bytes = LOwrite(newfd, (struct varlena *)buff);
+#endif
+ pfree (buff);
+ }
+ if (isDestLO)
+ if (ARR_IS_CHUNKED(array)) {
+ _ReadChunkArray(lowerIndx, upperIndx, len, fd, (char*)newfd, array,
+ 1,isNull);
+ } else {
+ _ReadArray(lowerIndx, upperIndx, len, fd, newfd, array, 1,isNull);
+ }
+#ifdef LOARRAY
+ (void) LOclose(fd);
+ (void) LOclose(newfd);
+#endif
+ if (*isNull) {
+ pfree(newArr);
+ newArr = NULL;
+ }
+ /* timer_end(); */
+ return ((Datum) newArr);
+ }
+
+ if (len > 0) {
+ bytes = getNitems(n, span);
+ bytes = bytes*len + ARR_OVERHEAD(n);
+ } else {
+ bytes = _ArrayClipCount(lowerIndx, upperIndx, array);
+ bytes += ARR_OVERHEAD(n);
+ }
+ newArr = (ArrayType *) palloc(bytes);
+ memmove(newArr, array, sizeof(ArrayType));
+ memmove(newArr, &bytes, sizeof(int));
+ memmove(ARR_DIMS(newArr), span, n*sizeof(int));
+ memmove(ARR_LBOUND(newArr), lowerIndx, n*sizeof(int));
+ _ArrayRange(lowerIndx, upperIndx, len, ARR_DATA_PTR(newArr), array, 1);
+ return (Datum) newArr;
+}
+
+/*-----------------------------------------------------------------------------
+ * array_set :
+ * This routine sets the value of an array location (specified by an index array)
+ * to a new value specified by "dataPtr".
+ * result :
+ * returns a pointer to the modified array.
+ *-----------------------------------------------------------------------------
+ */
+char *
+array_set(ArrayType *array,
+ int n,
+ int indx[],
+ char *dataPtr,
+ int reftype,
+ int elmlen,
+ int arraylen,
+ bool *isNull)
+{
+ int ndim, *dim, *lb, offset, nbytes;
+ char *pos;
+
+ if (array == (ArrayType *) NULL)
+ RETURN_NULL;
+ if (arraylen > 0) {
+ /*
+ * fixed length arrays -- these are assumed to be 1-d
+ */
+ if (indx[0]*elmlen > arraylen)
+ elog(WARN, "array_ref: array bound exceeded");
+ pos = (char *)array + indx[0]*elmlen;
+ ArrayCastAndSet(dataPtr, (bool) reftype, elmlen, pos);
+ return((char *)array);
+ }
+ dim = ARR_DIMS(array);
+ lb = ARR_LBOUND(array);
+ ndim = ARR_NDIM(array);
+ nbytes = (* (int32 *) array) - ARR_OVERHEAD(ndim);
+
+ if (!SanityCheckInput(ndim, n, dim, lb, indx))
+ return((char *)array);
+ offset = GetOffset( n, dim, lb, indx);
+
+ if (ARR_IS_LO(array)) {
+ int fd;
+ char * lo_name;
+ struct varlena *v;
+
+ /* We are assuming fixed element lengths here */
+ offset *= elmlen;
+#ifdef LOARRAY
+ lo_name = ARR_DATA_PTR(array);
+ if ((fd = LOopen(lo_name, ARR_IS_INV(array)?INV_WRITE:O_WRONLY)) < 0)
+ return((char *)array);
+#endif
+ if (lo_lseek(fd, offset, SEEK_SET) < 0)
+ return((char *)array);
+ v = (struct varlena *) palloc(elmlen + 4);
+ VARSIZE (v) = elmlen + 4;
+ ArrayCastAndSet(dataPtr, (bool) reftype, elmlen, VARDATA(v));
+#ifdef LOARRAY
+ n = LOwrite(fd, v);
+#endif
+ /* if (n < VARSIZE(v) - 4)
+ RETURN_NULL;
+ */
+ pfree(v);
+ (void) lo_close(fd);
+ return((char *)array);
+ }
+ if (elmlen > 0) {
+ offset = offset * elmlen;
+ /* off the end of the array */
+ if (nbytes - offset < 1) return((char *)array);
+ pos = ARR_DATA_PTR (array) + offset;
+ } else {
+ elog(WARN, "array_set: update of variable length fields not supported");
+ }
+ ArrayCastAndSet(dataPtr, (bool) reftype, elmlen, pos);
+ return((char *)array);
+}
+
+/*----------------------------------------------------------------------------
+ * array_assgn :
+ * This routine sets the value of a range of array locations (specified
+ * by upper and lower index values ) to new values passed as
+ * another array
+ * result :
+ * returns a pointer to the modified array.
+ *----------------------------------------------------------------------------
+ */
+char *
+array_assgn(ArrayType *array,
+ int n,
+ int upperIndx[],
+ int lowerIndx[],
+ ArrayType *newArr,
+ int reftype,
+ int len,
+ bool *isNull)
+{
+ int i, ndim, *dim, *lb;
+
+ if (array == (ArrayType *) NULL)
+ RETURN_NULL;
+ if (len < 0)
+ elog(WARN,"array_assgn:updates on arrays of variable length elements not allowed");
+
+ dim = ARR_DIMS(array);
+ lb = ARR_LBOUND(array);
+ ndim = ARR_NDIM(array);
+
+ if (!SanityCheckInput(ndim, n, dim, lb, upperIndx) ||
+ !SanityCheckInput(ndim, n, dim, lb, lowerIndx)) {
+ return((char *)array);
+ }
+
+ for (i = 0; i < n; i++)
+ if (lowerIndx[i] > upperIndx[i])
+ elog(WARN, "lowerIndex larger than upperIndx");
+
+ if (ARR_IS_LO(array)) {
+ char * lo_name;
+ int fd, newfd;
+
+#ifdef LOARRAY
+ lo_name = (char *)ARR_DATA_PTR(array);
+ if ((fd = LOopen(lo_name, ARR_IS_INV(array)?INV_WRITE:O_WRONLY)) < 0)
+ return((char *)array);
+#endif
+ if (ARR_IS_LO(newArr)) {
+#ifdef LOARRAY
+ lo_name = (char *)ARR_DATA_PTR(newArr);
+ if ((newfd = LOopen(lo_name, ARR_IS_INV(newArr)?INV_READ:O_RDONLY)) < 0)
+ return((char *)array);
+#endif
+ _LOArrayRange(lowerIndx, upperIndx, len, fd, newfd, array, 1, isNull);
+ (void) lo_close(newfd);
+ } else {
+ _LOArrayRange(lowerIndx, upperIndx, len, fd, (int)ARR_DATA_PTR(newArr),
+ array, 0, isNull);
+ }
+ (void) lo_close(fd);
+ return ((char *) array);
+ }
+ _ArrayRange(lowerIndx, upperIndx, len, ARR_DATA_PTR(newArr), array, 0);
+ return (char *) array;
+}
+
+/*-----------------------------------------------------------------------------
+ * array_eq :
+ * compares two arrays for equality
+ * result :
+ * returns 1 if the arrays are equal, 0 otherwise.
+ *-----------------------------------------------------------------------------
+ */
+int
+array_eq (ArrayType *array1, ArrayType *array2)
+{
+ if ((array1 == NULL) || (array2 == NULL))
+ return(0);
+ if (*(int *)array1 != *(int *)array2)
+ return (0);
+ if (memcmp(array1, array2, *(int *)array1))
+ return(0);
+ return(1);
+}
+
+/***************************************************************************/
+/******************| Support Routines |*****************/
+/***************************************************************************/
+static void
+system_cache_lookup(Oid element_type,
+ bool input,
+ int *typlen,
+ bool *typbyval,
+ char *typdelim,
+ Oid *typelem,
+ Oid *proc,
+ char *typalign)
+{
+ HeapTuple typeTuple;
+ TypeTupleForm typeStruct;
+
+ typeTuple = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(element_type),
+ 0,0,0);
+
+ if (!HeapTupleIsValid(typeTuple)) {
+ elog(WARN, "array_out: Cache lookup failed for type %d\n",
+ element_type);
+ return;
+ }
+ typeStruct = (TypeTupleForm) GETSTRUCT(typeTuple);
+ *typlen = typeStruct->typlen;
+ *typbyval = typeStruct->typbyval;
+ *typdelim = typeStruct->typdelim;
+ *typelem = typeStruct->typelem;
+ *typalign = typeStruct->typalign;
+ if (input) {
+ *proc = typeStruct->typinput;
+ } else {
+ *proc = typeStruct->typoutput;
+ }
+}
+
+static Datum
+_ArrayCast(char *value, bool byval, int len)
+{
+ if (byval) {
+ switch (len) {
+ case 1:
+ return((Datum) * value);
+ case 2:
+ return((Datum) * (int16 *) value);
+ case 3:
+ case 4:
+ return((Datum) * (int32 *) value);
+ default:
+ elog(WARN, "array_ref: byval and elt len > 4!");
+ break;
+ }
+ } else {
+ return (Datum) value;
+ }
+ return 0;
+}
+
+
+static int
+ArrayCastAndSet(char *src,
+ bool typbyval,
+ int typlen,
+ char *dest)
+{
+ int inc;
+
+ if (typlen > 0) {
+ if (typbyval) {
+ switch(typlen) {
+ case 1:
+ *dest = DatumGetChar(src);
+ break;
+ case 2:
+ * (int16 *) dest = DatumGetInt16(src);
+ break;
+ case 4:
+ * (int32 *) dest = (int32)src;
+ break;
+ }
+ } else {
+ memmove(dest, src, typlen);
+ }
+ inc = typlen;
+ } else {
+ memmove(dest, src, *(int32 *)src);
+ inc = (INTALIGN(* (int32 *) src));
+ }
+ return(inc);
+}
+
+static char *
+_AdvanceBy1word(char *str, char **word)
+{
+ char *retstr, *space;
+
+ *word = NULL;
+ if (str == NULL) return str;
+ while (isspace(*str)) str++;
+ *word = str;
+ if ((space = (char *)strchr(str, ' ')) != (char *) NULL) {
+ retstr = space + 1;
+ *space = '\0';
+ }
+ else
+ retstr = NULL;
+ return retstr;
+}
+
+int
+SanityCheckInput(int ndim, int n, int dim[], int lb[], int indx[])
+{
+ int i;
+ /* Do Sanity check on input */
+ if (n != ndim) return 0;
+ for (i = 0; i < ndim; i++)
+ if ((lb[i] > indx[i]) || (indx[i] >= (dim[i] + lb[i])))
+ return 0;
+ return 1;
+}
+
+static void
+_ArrayRange(int st[],
+ int endp[],
+ int bsize,
+ char *destPtr,
+ ArrayType *array,
+ int from)
+{
+ int n, *dim, *lb, st_pos, prod[MAXDIM];
+ int span[MAXDIM], dist[MAXDIM], indx[MAXDIM];
+ int i, j, inc;
+ char *srcPtr, *array_seek();
+
+ n = ARR_NDIM(array); dim = ARR_DIMS(array);
+ lb = ARR_LBOUND(array); srcPtr = ARR_DATA_PTR(array);
+ for (i = 0; i < n; st[i] -= lb[i], endp[i] -= lb[i], i++);
+ mda_get_prod(n, dim, prod);
+ st_pos = tuple2linear(n, st, prod);
+ srcPtr = array_seek(srcPtr, bsize, st_pos);
+ mda_get_range(n, span, st, endp);
+ mda_get_offset_values(n, dist, prod, span);
+ for (i=0; i < n; indx[i++]=0);
+ i = j = n-1; inc = bsize;
+ do {
+ srcPtr = array_seek(srcPtr, bsize, dist[j]);
+ if (from)
+ inc = array_read(destPtr, bsize, 1, srcPtr);
+ else
+ inc = array_read(srcPtr, bsize, 1, destPtr);
+ destPtr += inc; srcPtr += inc;
+ } while ((j = next_tuple(i+1, indx, span)) != -1);
+}
+
+static int
+_ArrayClipCount(int stI[], int endpI[], ArrayType *array)
+{
+ int n, *dim, *lb, st_pos, prod[MAXDIM];
+ int span[MAXDIM], dist[MAXDIM], indx[MAXDIM];
+ int i, j, inc, st[MAXDIM], endp[MAXDIM];
+ int count = 0;
+ char *ptr, *array_seek();
+
+ n = ARR_NDIM(array); dim = ARR_DIMS(array);
+ lb = ARR_LBOUND(array); ptr = ARR_DATA_PTR(array);
+ for (i = 0; i < n; st[i] = stI[i]-lb[i], endp[i]=endpI[i]-lb[i], i++);
+ mda_get_prod(n, dim, prod);
+ st_pos = tuple2linear(n, st, prod);
+ ptr = array_seek(ptr, -1, st_pos);
+ mda_get_range(n, span, st, endp);
+ mda_get_offset_values(n, dist, prod, span);
+ for (i=0; i < n; indx[i++]=0);
+ i = j = n-1;
+ do {
+ ptr = array_seek(ptr, -1, dist[j]);
+ inc = INTALIGN(* (int32 *) ptr);
+ ptr += inc; count += inc;
+ } while ((j = next_tuple(i+1, indx, span)) != -1);
+ return count;
+}
+
+char *
+array_seek(char *ptr, int eltsize, int nitems)
+{
+ int i;
+
+ if (eltsize > 0)
+ return(ptr + eltsize*nitems);
+ for (i = 0; i < nitems; i++)
+ ptr += INTALIGN(* (int32 *) ptr);
+ return(ptr);
+}
+
+int
+array_read(char *destptr, int eltsize, int nitems, char *srcptr)
+{
+ int i, inc, tmp;
+
+ if (eltsize > 0) {
+ memmove(destptr, srcptr, eltsize*nitems);
+ return(eltsize*nitems);
+ }
+ for (i = inc = 0; i < nitems; i++) {
+ tmp = (INTALIGN(* (int32 *) srcptr));
+ memmove(destptr, srcptr, tmp);
+ srcptr += tmp;
+ destptr += tmp;
+ inc += tmp;
+ }
+ return(inc);
+}
+
+static void
+_LOArrayRange(int st[],
+ int endp[],
+ int bsize,
+ int srcfd,
+ int destfd,
+ ArrayType *array,
+ int isSrcLO,
+ bool *isNull)
+{
+ int n, *dim, st_pos, prod[MAXDIM];
+ int span[MAXDIM], dist[MAXDIM], indx[MAXDIM];
+ int i, j, inc, tmp, *lb, offset;
+
+ n = ARR_NDIM(array); dim = ARR_DIMS(array);
+ lb = ARR_LBOUND(array);
+ for (i = 0; i < n; st[i] -= lb[i], endp[i] -= lb[i], i++);
+
+ mda_get_prod(n, dim, prod);
+ st_pos = tuple2linear(n, st, prod);
+ offset = st_pos*bsize;
+ if (lo_lseek(srcfd, offset, SEEK_SET) < 0)
+ return;
+ mda_get_range(n, span, st, endp);
+ mda_get_offset_values(n, dist, prod, span);
+ for (i=0; i < n; indx[i++]=0);
+ for (i = n-1, inc = bsize; i >= 0; inc *= span[i--])
+ if (dist[i])
+ break;
+ j = n-1;
+ do {
+ offset += (dist[j]*bsize);
+ if (lo_lseek(srcfd, offset, SEEK_SET) < 0)
+ return;
+ tmp = _LOtransfer((char**)&srcfd, inc, 1, (char**)&destfd, isSrcLO, 1);
+ if ( tmp < inc )
+ return;
+ offset += inc;
+ } while ((j = next_tuple(i+1, indx, span)) != -1);
+}
+
+
+static void
+_ReadArray (int st[],
+ int endp[],
+ int bsize,
+ int srcfd,
+ int destfd,
+ ArrayType *array,
+ int isDestLO,
+ bool *isNull)
+{
+ int n, *dim, st_pos, prod[MAXDIM];
+ int span[MAXDIM], dist[MAXDIM], indx[MAXDIM];
+ int i, j, inc, tmp, *lb, offset;
+
+ n = ARR_NDIM(array); dim = ARR_DIMS(array);
+ lb = ARR_LBOUND(array);
+ for (i = 0; i < n; st[i] -= lb[i], endp[i] -= lb[i], i++);
+
+ mda_get_prod(n, dim, prod);
+ st_pos = tuple2linear(n, st, prod);
+ offset = st_pos*bsize;
+ if (lo_lseek(srcfd, offset, SEEK_SET) < 0)
+ return;
+ mda_get_range(n, span, st, endp);
+ mda_get_offset_values(n, dist, prod, span);
+ for (i=0; i < n; indx[i++]=0);
+ for (i = n-1, inc = bsize; i >= 0; inc *= span[i--])
+ if (dist[i])
+ break;
+ j = n-1;
+ do {
+ offset += (dist[j]*bsize);
+ if (lo_lseek(srcfd, offset, SEEK_SET) < 0)
+ return;
+ tmp = _LOtransfer((char**)&destfd, inc, 1, (char**)&srcfd, 1, isDestLO);
+ if ( tmp < inc )
+ return;
+ offset += inc;
+ } while ((j = next_tuple(i+1, indx, span)) != -1);
+}
+
+
+int
+_LOtransfer(char **destfd,
+ int size,
+ int nitems,
+ char **srcfd,
+ int isSrcLO,
+ int isDestLO)
+{
+#define MAX_READ (512 * 1024)
+#define min(a, b) (a < b ? a : b)
+ struct varlena *v;
+ int tmp, inc, resid;
+
+ inc = nitems*size;
+ if (isSrcLO && isDestLO && inc > 0)
+ for (tmp = 0, resid = inc;
+ resid > 0 && (inc = min(resid, MAX_READ)) > 0; resid -= inc) {
+#ifdef LOARRAY
+ v = (struct varlena *) LOread((int) *srcfd, inc);
+ if (VARSIZE(v) - 4 < inc)
+ {pfree(v); return(-1);}
+ tmp += LOwrite((int) *destfd, v);
+#endif
+ pfree(v);
+
+ }
+ else if (!isSrcLO && isDestLO) {
+ tmp = lo_write((int) *destfd, *srcfd, inc);
+ *srcfd = *srcfd + tmp;
+ }
+ else if (isSrcLO && !isDestLO) {
+ tmp = lo_read((int) *srcfd, *destfd, inc);
+ *destfd = *destfd + tmp;
+ }
+ else {
+ memmove(*destfd, *srcfd, inc);
+ tmp = inc;
+ *srcfd += inc;
+ *destfd += inc;
+ }
+ return(tmp);
+#undef MAX_READ
+}
+
+char *
+_array_newLO(int *fd, int flag)
+{
+ char *p;
+ char saveName[NAME_LEN];
+
+ p = (char *) palloc(NAME_LEN);
+ sprintf(p, "/Arry.%d", newoid());
+ strcpy (saveName, p);
+#ifdef LOARRAY
+ if ( (*fd = LOcreat (saveName, 0600, flag)) < 0)
+ elog(WARN, "Large object create failed");
+#endif
+ return (p);
+}
+