head 1.34; access; symbols release_4_2:1.34 marc_alpha:1.25 aix_ok:1.28; locks; strict; comment @ * @; 1.34 date 94.06.23.02.48.02; author aoki; state Exp; branches; next 1.33; 1.33 date 94.06.16.03.23.06; author aoki; state Exp; branches; next 1.32; 1.32 date 94.03.29.20.45.00; author sunita; state Exp; branches; next 1.31; 1.31 date 94.03.17.22.18.25; author sklower; state Exp; branches; next 1.30; 1.30 date 94.02.10.02.49.49; author sunita; state Exp; branches; next 1.29; 1.29 date 93.11.05.08.37.42; author aoki; state Exp; branches; next 1.28; 1.28 date 93.09.28.01.49.19; author sklower; state Exp; branches; next 1.27; 1.27 date 93.08.23.02.07.34; author sunita; state Exp; branches; next 1.26; 1.26 date 93.08.16.20.51.53; author sunita; state Exp; branches; next 1.25; 1.25 date 93.08.10.01.46.51; author marc; state Exp; branches; next 1.24; 1.24 date 93.07.26.23.54.52; author aoki; state Exp; branches; next 1.23; 1.23 date 93.06.23.18.47.31; author sunita; state Exp; branches; next 1.22; 1.22 date 93.04.14.01.23.04; author sunita; state Exp; branches; next 1.21; 1.21 date 93.01.16.03.14.59; author aoki; state Exp; branches; next 1.20; 1.20 date 92.12.15.02.32.06; author aoki; state Exp; branches; next 1.19; 1.19 date 92.08.07.02.31.23; author mer; state Exp; branches; next 1.18; 1.18 date 92.05.06.05.09.55; author mer; state Exp; branches; next 1.17; 1.17 date 92.04.03.07.31.58; author mer; state Exp; branches; next 1.16; 1.16 date 92.04.03.01.06.24; author mer; state Exp; branches; next 1.15; 1.15 date 92.03.16.19.09.47; author mer; state Exp; branches; next 1.14; 1.14 date 92.03.16.05.21.53; author mer; state Exp; branches; next 1.13; 1.13 date 92.03.16.04.52.29; author mer; state Exp; branches; next 1.12; 1.12 date 92.02.17.13.47.42; author mer; state Exp; branches; next 1.11; 1.11 date 92.02.15.22.54.45; author mer; state Exp; branches; next 1.10; 1.10 date 91.12.15.02.00.59; author glass; state Exp; branches; next 1.9; 1.9 date 91.11.09.01.45.54; author mer; state Exp; branches; next 1.8; 1.8 date 91.04.11.01.37.01; author kemnitz; state Exp; branches; next 1.7; 1.7 date 91.04.04.18.26.16; author kemnitz; state Exp; branches; next 1.6; 1.6 date 91.03.30.17.27.44; author kemnitz; state Exp; branches; next 1.5; 1.5 date 91.03.28.13.52.34; author kemnitz; state Exp; branches; next 1.4; 1.4 date 91.03.27.02.32.21; author kemnitz; state Exp; branches; next 1.3; 1.3 date 91.03.27.02.12.55; author kemnitz; state Exp; branches; next 1.2; 1.2 date 91.03.26.12.49.24; author kemnitz; state Exp; branches; next 1.1; 1.1 date 91.03.26.11.04.04; author kemnitz; state Exp; branches; next ; desc @Generalized array input/output functions @ 1.34 log @uninit var @ text @ /* * arrayfuncs.c -- * Special functions for arrays. * * * RcsId("$Header: /faerie/aoki/postgres/src/backend/utils/adt/RCS/arrayfuncs.c,v 1.33 1994/06/16 03:23:06 aoki Exp aoki $"); */ #include #include #include "tmp/postgres.h" #include "tmp/libpq-fs.h" #include "catalog/pg_type.h" #include "catalog/syscache.h" #include "catalog/pg_lobj.h" #include "utils/palloc.h" #include "utils/memutils.h" #include "storage/fd.h" /* for SEEK_ */ #include "fmgr.h" #include "utils/log.h" #include "array.h" #define ASSGN "=" /* An array has the following internal structure: * - total number of bytes * - number of dimensions of the array * - bit mask of flags * - size of each array axis * - lower boundary of each dimension * - whatever is the stored data */ /*-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-*/ char *_array_newLO(), *_ChunkArray(), * array_dims(); struct varlena * _ReadChunkArray1El(); Datum _ArrayCast(); /*--------------------------------------------------------------------- * 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(string, element_type) char *string; /* input array in external form */ ObjectId element_type; /* type OID of an array element */ { int typlen; bool typbyval, done; char typdelim; ObjectId typinput; ObjectId 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 *_ReadLOArray(), *_ReadArrayStr(); system_cache_lookup(element_type, true, &typlen, &typbyval, &typdelim, &typelem, &typinput); 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 *)index(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)); bzero(emptyArray, 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, &nbytes ); nbytes += ARR_OVERHEAD(ndim); retval = (ArrayType *) palloc(nbytes); bzero (retval, nbytes); bcopy(&nbytes, retval, sizeof(int)); bcopy(&ndim, ARR_NDIM_PTR(retval), sizeof(int)); SET_LO_FLAG (false, retval); bcopy(dim, ARR_DIMS(retval), ndim*sizeof(int)); bcopy(lBound, ARR_LBOUND(retval), ndim*sizeof(int)); _CopyArrayEls(dataPtr, ARR_DATA_PTR(retval), nitems, typlen, typbyval); } else { int dummy, bytes, lobjtype; bool chunked = false; dataPtr = _ReadLOArray(p, &bytes, &dummy, &chunked, &lobjtype, ndim, dim, typlen ); nbytes = bytes + ARR_OVERHEAD(ndim); retval = (ArrayType *) palloc(nbytes); bzero (retval, nbytes); bcopy(&nbytes, retval, sizeof(int)); bcopy(&ndim, ARR_NDIM_PTR(retval), sizeof(int)); SET_LO_FLAG (true, retval); SET_CHUNK_FLAG (chunked, retval); SET_OBJ_TYPE (lobjtype, retval); bcopy(dim, ARR_DIMS(retval), ndim*sizeof(int)); bcopy(lBound, ARR_LBOUND(retval), ndim*sizeof(int)); bcopy(dataPtr, ARR_DATA_PTR(retval), bytes); } 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 *-------------------------------------------------------------------------------- */ int _ArrayCount(str, dim, typdelim) int dim[], typdelim; char *str; { 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. *----------------------------------------------------------------------------*/ char * _ReadArrayStr(arrayStr, nitems, ndim, dim, inputproc, typelem, typdelim, typlen, typbyval, nbytes) int nitems, ndim, dim[], typlen, *nbytes; ObjectId typelem; char typdelim, *arrayStr; func_ptr inputproc; /* function used for the conversion */ bool typbyval; { int i, dummy, nest_level = 0; char *p, *q, *r, **values; bool scanning_string = false; int indx[MAXDIM], prod[MAXDIM]; bool eoArray = false; get_prod(ndim, dim, prod); for (i = 0; i < ndim; indx[i++] = 0); /* read array enclosed within {} */ values = (char **) palloc(nitems * sizeof(char *)); bzero(values, 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); bzero(values[i], typlen); } } else { for (i = 0, *nbytes = 0; i < nitems; i++) { if (values[i]) *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 *-------------------------------------------------------------------------------- */ char * _ReadLOArray(str, nbytes, fd, chunkFlag, lobjtype, ndim, dim, baseSize ) char *str; int *nbytes, *fd, *lobjtype; bool *chunkFlag; int ndim, dim[], baseSize; { char *inputfile, *accessfile = NULL, *chunkfile = NULL; char *retStr, *_AdvanceBy1word(); *lobjtype = Unix; /* default */ str = _AdvanceBy1word(str, &inputfile); while (str != NULL) { char *space, *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 if (!strcmp(word, "-invert")) *lobjtype = Inversion; else if (!strcmp(word, "-unix")) *lobjtype = Unix; else if (!strcmp(word, "-external")) *lobjtype = External; else if (!strcmp(word, "-jaquith")) *lobjtype = Jaquith; else { *lobjtype = Unix; elog(WARN, "usage: -chunk DEFAULT/ -invert/-native [-noreorg ]"); } } if (inputfile == NULL) elog(WARN, "array_in: missing file name"); *fd = -1; if (FilenameToOID(inputfile) == InvalidObjectId) { char * saveName = palloc(strlen(inputfile) + 2); strcpy (saveName, inputfile); if (*lobjtype == Inversion) *fd = LOcreat (saveName, INV_READ, *lobjtype); else *fd = LOcreat (saveName, 0600, *lobjtype); if ( *fd < 0 ) elog(WARN, "Large object create failed"); pfree(saveName); } 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; if (*fd == -1) if ((*fd = LOopen(inputfile, (*lobjtype == Inversion)?INV_READ:O_RDONLY)) < 0) elog(WARN, "array_in:Unable to open input file"); retStr = _ChunkArray(*fd, afd, ndim, dim, baseSize, nbytes, *lobjtype, chunkfile); } return(retStr); } /*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/ _CopyArrayEls( values, p, nitems, typlen, typbyval) bool typbyval; int nitems, typlen; char *p, **values; { int i; for (i = 0; i < nitems; i++) { int inc; inc = ArrayCastAndSet((char *)values[i], typbyval, typlen, p); p += inc; if (!typbyval) pfree((char *)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(v, element_type) ArrayType *v; ObjectId element_type; { int typlen; bool typbyval; char typdelim; ObjectId typoutput, typelem; func_ptr outputproc; char *p, *q, *retval, **values, delim[2]; int nitems, nbytes, overall_length, i, j, k, dummy, indx[MAXDIM]; int ndim, *dim, *lBound; if (v == (ArrayType *) NULL) return ((char *) NULL); if (ARR_IS_LO(v) == true) { char *p, *save_p; int nbytes, i; /* get a wide string to print to */ p = array_dims(v, &dummy); 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); fmgr_info(typoutput, & outputproc, &dummy); 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 = 0; 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((char *)values); return(retval); } /*--------------------------------------------------------------------------------- * array_dims : * returns the dimension of the array pointed to by "v" *--------------------------------------------------------------------------------- */ char * array_dims(v, isNull) 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); bzero(save_p, 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; bcopy(&nbytes, save_p, 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(array, n, indx, reftype, elmlen, arraylen, isNull) ArrayType *array; int indx[], n; int reftype, elmlen, 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); if ((fd = LOopen(lo_name, ARR_IS_INV(array)?INV_READ:O_RDONLY)) < 0) RETURN_NULL; if (ARR_IS_CHUNKED(array)) v = _ReadChunkArray1El(indx, elmlen, fd, array, isNull); else { if (LOlseek(fd, offset, SEEK_SET) < 0) RETURN_NULL; v = (struct varlena *) LOread(fd, elmlen); } if (*isNull) RETURN_NULL; if (VARSIZE(v) - 4 < elmlen) RETURN_NULL; (void) LOclose(fd); retval = (char *)_ArrayCast((char *)VARDATA(v), reftype, elmlen); if ( reftype == 0) { /* not by value */ char * tempdata = palloc (elmlen); bcopy (retval, tempdata, 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(array, n, upperIndx, lowerIndx, reftype, len, isNull) ArrayType *array; int upperIndx[], lowerIndx[], n; int reftype, len; bool *isNull; { int i, ndim, *dim, *lb, offset, nbytes; struct varlena *v; char *retval; 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"); 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"); 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 ); bytes = strlen(newname) + 1 + ARR_OVERHEAD(n); newArr = (ArrayType *) palloc(bytes); bcopy(array, newArr, sizeof(ArrayType)); bcopy(&bytes, newArr, sizeof(int)); bcopy(span, ARR_DIMS(newArr), n*sizeof(int)); bcopy(lowerIndx, ARR_LBOUND(newArr), 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, &(buff[4]),array, 0,isNull); } bcopy (&rsize, buff, 4); if (! *isNull) bytes = LOwrite ( newfd, buff ); pfree (buff); } if (isDestLO) if (ARR_IS_CHUNKED(array)) { _ReadChunkArray(lowerIndx, upperIndx, len, fd, newfd, array, 1,isNull); } else { _ReadArray(lowerIndx, upperIndx, len, fd, newfd, array, 1,isNull); } (void) LOclose(fd); (void) LOclose(newfd); 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); bcopy(array, newArr, sizeof(ArrayType)); bcopy(&bytes, newArr, sizeof(int)); bcopy(span, ARR_DIMS(newArr), n*sizeof(int)); bcopy(lowerIndx, ARR_LBOUND(newArr), 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(array, n, indx, dataPtr, reftype, elmlen, arraylen, isNull) ArrayType *array; int n, indx[]; bool *isNull; char *dataPtr; int reftype, elmlen, arraylen; { int i, 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; lo_name = ARR_DATA_PTR(array); if ((fd = LOopen(lo_name, ARR_IS_INV(array)?INV_WRITE:O_WRONLY)) < 0) return((char *)array); if (LOlseek(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)); n = LOwrite(fd, v); /* if (n < VARSIZE(v) - 4) RETURN_NULL; */ pfree(v); (void) LOclose(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(array, n, upperIndx, lowerIndx, newArr, reftype, len, isNull) ArrayType *array, *newArr; int upperIndx[], lowerIndx[], n; int reftype, 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; lo_name = (char *)ARR_DATA_PTR(array); if ((fd = LOopen(lo_name, ARR_IS_INV(array)?INV_WRITE:O_WRONLY)) < 0) return((char *)array); if (ARR_IS_LO(newArr)) { lo_name = (char *)ARR_DATA_PTR(newArr); if ((newfd = LOopen(lo_name, ARR_IS_INV(newArr)?INV_READ:O_RDONLY)) < 0) return((char *)array); _LOArrayRange(lowerIndx, upperIndx, len, fd, newfd, array, 1, isNull); (void) LOclose(newfd); } else { _LOArrayRange(lowerIndx, upperIndx, len, fd, ARR_DATA_PTR(newArr), array, 0, isNull); } (void) LOclose(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. *-------------------------------------------------------------------------------- */ array_eq ( array1, array2 ) ArrayType *array1, *array2; { if ((array1 == NULL) || (array2 == NULL)) return(0); if ( *(int *)array1 != *(int *)array2 ) return (0); if ( bcmp(array1, array2, *(int *)array1)) return(0); return(1); } /***************************************************************************/ /******************| Support Routines |*****************/ /***************************************************************************/ system_cache_lookup(element_type, input, typlen, typbyval, typdelim, typelem, proc) ObjectId element_type; Boolean input; int *typlen; bool *typbyval; char *typdelim; ObjectId *typelem; ObjectId *proc; { HeapTuple typeTuple; TypeTupleForm typeStruct; typeTuple = SearchSysCacheTuple(TYPOID, element_type, NULL, NULL, NULL); if (!HeapTupleIsValid(typeTuple)) { elog(WARN, "array_out: Cache lookup failed for type %d\n", element_type); return NULL; } typeStruct = (TypeTupleForm) GETSTRUCT(typeTuple); *typlen = typeStruct->typlen; *typbyval = typeStruct->typbyval; *typdelim = typeStruct->typdelim; *typelem = typeStruct->typelem; if (input) { *proc = typeStruct->typinput; } else { *proc = typeStruct->typoutput; } } /*****************************************************************************/ Datum _ArrayCast(value, byval, len) 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; } } /******************************************************************************/ ArrayCastAndSet(src, typbyval, typlen, dest) char *src, *dest; int typlen; bool typbyval; { 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 { bcopy(src, dest, typlen); } inc = typlen; } else { bcopy(src, dest, * (int32 *) src); inc = (INTALIGN(* (int32 *) src)); } return(inc); } /***************************************************************************/ char * _AdvanceBy1word(str, word) char *str, **word; { char *retstr, *space; *word = NULL; if (str == NULL) return str; while (isspace(*str)) str++; *word = str; if ((space = (char *)index(str, ' ')) != (char *) NULL) { retstr = space + 1; *space = '\0'; } else retstr = NULL; return retstr; } /************************************************************************/ SanityCheckInput(ndim, n, dim, lb, indx) int ndim, n, dim[], lb[], 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; } /***********************************************************************/ _ArrayRange(st, endp, bsize, destPtr, array, from) int st[], endp[], bsize, from; char * destPtr; ArrayType *array; { 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++); get_prod(n, dim, prod); st_pos = tuple2linear(n, st, prod); srcPtr = array_seek(srcPtr, bsize, st_pos); get_range(n, span, st, endp); 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); } /***********************************************************************/ _ArrayClipCount(stI, endpI, array) int stI[], 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++); get_prod(n, dim, prod); st_pos = tuple2linear(n, st, prod); ptr = array_seek(ptr, -1, st_pos); get_range(n, span, st, endp); 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(ptr, eltsize, nitems) int eltsize, nitems; char *ptr; { int i; if (eltsize > 0) return(ptr + eltsize*nitems); for (i = 0; i < nitems; i++) ptr += INTALIGN(* (int32 *) ptr); return(ptr); } /***********************************************************************/ array_read(destptr, eltsize, nitems, srcptr) int eltsize, nitems; char *srcptr, *destptr; { int i, inc, tmp; if (eltsize > 0) { bcopy(srcptr, destptr, eltsize*nitems); return(eltsize*nitems); } for (i = inc = 0; i < nitems; i++) { tmp = (INTALIGN(* (int32 *) srcptr)); bcopy(srcptr, destptr, tmp); srcptr += tmp; destptr += tmp; inc += tmp; } return(inc); } /***********************************************************************/ _LOArrayRange(st, endp, bsize, srcfd, destfd, array, isSrcLO, isNull) int st[], endp[], bsize, isSrcLO; int srcfd, destfd; ArrayType *array; 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++); get_prod(n, dim, prod); st_pos = tuple2linear(n, st, prod); offset = st_pos*bsize; if (LOlseek(srcfd, offset, SEEK_SET) < 0) return; get_range(n, span, st, endp); 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 (LOlseek(srcfd, offset, SEEK_SET) < 0) return; tmp = _LOtransfer(&srcfd, inc, 1, &destfd, isSrcLO, 1); if ( tmp < inc ) return; offset += inc; } while ((j = next_tuple(i+1, indx, span)) != -1); } /***********************************************************************/ _ReadArray (st, endp, bsize, srcfd, destfd, array, isDestLO, isNull) int st[], endp[], bsize, isDestLO; int srcfd, destfd; ArrayType *array; 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++); get_prod(n, dim, prod); st_pos = tuple2linear(n, st, prod); offset = st_pos*bsize; if (LOlseek(srcfd, offset, SEEK_SET) < 0) RETURN_NULL; get_range(n, span, st, endp); 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 (LOlseek(srcfd, offset, SEEK_SET) < 0) RETURN_NULL; tmp = _LOtransfer(&destfd, inc, 1, &srcfd, 1, isDestLO); if ( tmp < inc ) RETURN_NULL; offset += inc; } while ((j = next_tuple(i+1, indx, span)) != -1); } /***********************************************************************/ _LOtransfer(destfd, size, nitems, srcfd, isSrcLO, isDestLO) char **destfd, **srcfd; int size, nitems, isSrcLO, 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) { v = (struct varlena *) LOread((int) *srcfd, inc); if (VARSIZE(v) - 4 < inc) {pfree(v); return(-1);} tmp += LOwrite((int) *destfd, v); pfree(v); } else if (!isSrcLO && isDestLO) { tmp = LO_write(*srcfd, inc, (int) *destfd); *srcfd = *srcfd + tmp; } else if (isSrcLO && !isDestLO) { tmp = LO_read(*destfd, inc, (int) *srcfd); *destfd = *destfd + tmp; } else { bcopy(*srcfd, *destfd, inc); tmp = inc; *srcfd += inc; *destfd += inc; } return(tmp); #undef MAX_READ } /***********************************************************************/ char * _array_set(array, indx_str, dataPtr) ArrayType *array; struct varlena *indx_str, *dataPtr; { int len, i; int indx[MAXDIM]; char *retval, *s, *comma, *r; bool isNull; /* convert index string to index array */ s = VARDATA(indx_str); for (i=0; *s != '\0'; i++) { while (isspace(*s)) s++; r = s; if ((comma = (char *)index(s, ',')) != (char *) NULL) { *comma = '\0'; s = comma + 1; } else while (*s != '\0') s++; if ((indx[i] = atoi(r)) < 0) elog(WARN, "array dimensions must be non-negative"); } retval = array_set(array, i, indx, dataPtr, &isNull); return(retval); } /***************************************************************************/ char * _array_newLO(fd, flag) int *fd; int flag; { char *p; char saveName[NAME_LEN]; p = (char *) palloc(NAME_LEN); sprintf(p, "/Arry.%d", newoid()); strcpy (saveName, p); if ( (*fd = LOcreat (saveName, 0600, flag)) < 0) elog(WARN, "Large object create failed"); return (p); } /**********************************************************************/ @ 1.33 log @SEEK_SET @ text @d6 1 a6 1 * RcsId("$Header: /faerie/aoki/postgres/src/backend/utils/adt/RCS/arrayfuncs.c,v 1.32 1994/03/29 20:45:00 sunita Exp aoki $"); a1301 1 struct varlena *v; a1321 1 pfree(v); @ 1.32 log @changed semantics of array replace slightly @ text @d6 1 a6 1 * RcsId("$Header: /private/src/postgres/src/backend/utils/adt/RCS/arrayfuncs.c,v 1.31 1994/03/17 22:18:25 sklower Exp sunita $"); d11 1 d21 1 d659 1 a659 1 if (LOlseek(fd, offset, L_SET) < 0) d864 1 a864 1 if (LOlseek(fd, offset, L_SET) < 0) d1198 1 a1198 1 if (LOlseek(srcfd, offset, L_SET) < 0) d1209 1 a1209 1 if (LOlseek(srcfd, offset, L_SET) < 0) d1236 1 a1236 1 if (LOlseek(srcfd, offset, L_SET) < 0) d1247 1 a1247 1 if (LOlseek(srcfd, offset, L_SET) < 0) @ 1.31 log @clip larger objects than you may be able to palloc() @ text @d6 1 a6 1 * RcsId("$Header: /private/src/postgres/src/backend/utils/adt/RCS/arrayfuncs.c,v 1.30 1994/02/10 02:49:49 sunita Exp sklower$"); d868 1 a868 1 if (n < VARSIZE(v) - 4) d870 1 d1197 1 a1197 1 RETURN_NULL; d1208 1 a1208 1 RETURN_NULL; d1211 1 a1211 1 RETURN_NULL; @ 1.30 log @was pfree-ing memory prematurely at some place -- fixed it. @ text @d6 1 a6 1 * RcsId("$Header: /private/src/postgres/src/backend/utils/adt/RCS/arrayfuncs.c,v 1.29 1993/11/05 08:37:42 aoki Exp sunita $"); d1258 2 d1261 1 a1261 1 int tmp, inc; d1264 10 a1273 7 if (isSrcLO && isDestLO) { v = (struct varlena *) LOread((int) *srcfd, inc); if (VARSIZE(v) - 4 < inc) return(-1); tmp = LOwrite((int) *destfd, v); pfree(v); } d1289 1 @ 1.29 log @large object type wasn't being initialized, with rather odd results on different architectures. @ text @d6 1 a6 1 * RcsId("$Header: /faerie/aoki/postgres/src/backend/utils/adt/RCS/arrayfuncs.c,v 1.28 1993/09/28 01:49:19 sklower Exp aoki $"); d666 6 a671 1 pfree(v); @ 1.28 log @changes to arrays to allow ``External'' and ``Jaquith'' large objects as stores @ text @d6 1 a6 1 * RcsId("$Header: /private/src/postgres/src/backend/utils/adt/RCS/arrayfuncs.c,v 1.27 1993/08/23 02:07:34 sunita Exp $"); a143 1 bool inversion = false; d363 2 @ 1.27 log @chunked a flag in large_object_array creation. @ text @d6 1 a6 1 * RcsId("$Header: /private/src/postgres/src/backend/utils/adt/RCS/arrayfuncs.c,v 1.26 1993/08/16 20:51:53 sunita Exp sunita $"); d142 1 a142 1 int dummy, bytes; d146 1 a146 1 dataPtr = _ReadLOArray(p, &bytes, &dummy, &chunked, &inversion, ndim, d155 1 a155 1 SET_INV_FLAG (inversion, retval); d355 1 a355 1 _ReadLOArray(str, nbytes, fd, chunkFlag, invFlag, ndim, dim, baseSize ) d357 2 a358 2 int *nbytes, *fd; bool *chunkFlag, *invFlag; a362 1 int fileFlag; a363 2 *invFlag = 0; d383 1 a383 1 *invFlag = true; d385 7 a391 2 *invFlag = false; else d393 1 a398 4 if (*invFlag) fileFlag = Inversion; else fileFlag = Unix; d402 2 a403 2 if (*invFlag) *fd = LOcreat (saveName, INV_READ, fileFlag); d405 1 a405 1 *fd = LOcreat (saveName, 0600, fileFlag); d419 2 a420 1 if ((*fd = LOopen(inputfile, (*invFlag)?INV_READ:O_RDONLY)) < 0) d422 1 a422 1 retStr = _ChunkArray(*fd, afd, ndim, dim, baseSize, nbytes, fileFlag, chunkfile); @ 1.26 log @corrected a bug in array_eq() @ text @d6 1 a6 1 * RcsId("$Header: /private/src/postgres/src/backend/utils/adt/RCS/arrayfuncs.c,v 1.25 1993/08/10 01:46:51 marc Exp sunita $"); d387 1 a387 1 else if (!strcmp(word, "-native")) @ 1.25 log @alpha port @ text @d6 1 a6 1 * RcsId("$Header: /usr/local/devel/postgres.alpha.merge/src/backend/utils/adt/RCS/arrayfuncs.c,v 1.24 1993/07/26 23:54:52 aoki Exp marc $"); d950 1 a950 1 if ( strncmp(array1, array2, *(int *)array1)) return(0); @ 1.24 log @hpux evaluates postincrement differently from ultrix etc. changed some for() loops for portability @ text @d6 1 a6 1 * RcsId("$Header: /faerie/hpux/postgres/src/backend/utils/adt/RCS/arrayfuncs.c,v 1.23 1993/06/23 18:47:31 sunita Exp aoki $"); a11 1 #include "tmp/align.h" d19 1 d338 1 a338 1 *nbytes += LONGALIGN(* (int *) values[i]); d340 3 a342 3 *nbytes += sizeof(int); values[i] = palloc(sizeof(int)); *(int *)values[i] = sizeof(int); d524 1 a524 1 p += LONGALIGN(* (int32 *) p); d686 2 a687 2 bytes -= LONGALIGN(* (int32 *) temp); temp += LONGALIGN(* (int32 *) temp); d1040 1 a1040 1 inc = (LONGALIGN(* (int32 *) src)); d1131 1 a1131 1 inc = LONGALIGN(* (int *) ptr); d1148 1 a1148 1 ptr += LONGALIGN(* (int *) ptr); d1163 1 a1163 1 tmp = (LONGALIGN(* (int *) srcptr)); @ 1.23 log @added array chunking support, made array input/output functions more intelligent, added support for fixed length arrays like int28, char16 etc and fixed some old stuff. .. @ text @d6 1 a6 1 * RcsId("$Header: /private/src/postgres/src/backend/utils/adt/RCS/arrayfuncs.c,v 1.22 1993/04/14 01:23:04 sunita Exp sunita $"); d181 3 a183 1 for (i = 0; i < MAXDIM; temp[i] = dim[i++] = 0); d222 4 a225 1 for (i = 0; i < ndim; dim[i] = temp[i++]); @ 1.22 log @All array functions defined here -- lots of new features. @ text @d3 1 a3 1 * Special array in and out functions for arrays. d6 1 a6 1 * RcsId("$Header: /usr/local/devel/postgres/src/backend/utils/adt/RCS/arrayfuncs.c,v 1.21 1993/01/16 03:14:59 aoki Exp $"); d10 1 d24 1 a24 3 char * _ReadLOArray(), * _ReadArrayString(), * array_seek(), * _array_newLO(); Datum _ArrayCast(); d27 6 a32 6 * - total number of bytes * - number of dimensions of the array * - boolean flag to idicate if array is LO-type * - size of each array axis * - lower boundary of each dimension * - whatever is the stored data d36 3 d40 8 d50 2 a51 2 char *string; ObjectId element_type; a53 1 static ObjectId charTypid = InvalidObjectId; d55 1 a55 1 bool typbyval, done, isLO = false; d64 3 a66 2 ArrayType *retval; int ndim, dim[MAXDIM], lBound[MAXDIM]; d68 2 a69 2 system_cache_lookup(element_type, true, &typlen, &typbyval, &typdelim, &typelem, &typinput); d71 1 a71 1 fmgr_info(typinput, & inputproc, &dummy); d76 14 a89 14 /* --- read array dimensions ---------- */ p = q = string_save; done = false; for (ndim = 0; !done; ){ while (isSpace(*p)) p++; switch (*p) { case '[': p++; if ((r = (char *)index(p, ':')) == (char *)NULL) lBound[ndim] = 1; else { *r = '\0'; lBound[ndim] = atoi(p); p = r + 1; } for (q = p; isNumber(*q); q++); d94 5 a98 5 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 less than lower bound"); d100 2 a101 4 break; default: done = true; break; d104 1 d106 66 a171 54 if (*p == '{') { ndim = _ArrayCount(p, dim, typdelim); if (ndim == 0) elog(WARN, "array_in: Cannot determine array dimensions from input"); for (i = 0; i < ndim; lBound[i++] = 1); } else elog(WARN, "array_in: Need to specify array dimension or enclose within '{' '}'"); } else { while (isSpace(*p)) p++; if (*p == '\0') elog(WARN, "array_in: missing assignment operator"); if (*p != '=') elog(WARN, "array_in: missing assignment operator"); p++; while (isSpace(*p)) p++; } getNitems(nitems, ndim, dim); if (nitems == 0) { char *emptyArray = palloc(sizeof(ArrayType)); bzero(emptyArray, sizeof(ArrayType)); * (int32 *) emptyArray = sizeof(ArrayType); return emptyArray; } if (*p == '{') dataPtr = (char *) _ReadArrayString(p, nitems, inputproc, typelem,typdelim, typlen, typbyval, &nbytes ); else { int dummy; dataPtr = (char *)_ReadLOArray(p, &nbytes, &dummy); isLO = true; } nbytes += ARR_OVERHEAD(ndim); retval = (ArrayType *) palloc(nbytes); bzero (retval, nbytes); bcopy(&nbytes, retval, sizeof(int)); bcopy(&ndim, ARR_NDIM_PTR(retval), sizeof(int)); bcopy(&isLO, ARR_IS_LO_PTR(retval), sizeof(bool)); bcopy(dim, ARR_DIMS(retval), ndim*sizeof(int)); bcopy(lBound, ARR_LBOUND(retval), ndim*sizeof(int)); _CopyArrayValues(isLO, dataPtr, ARR_DATA_PTR(retval), nitems, typlen, typbyval); pfree(string_save); return((char *)retval); } /*-==-=-=-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-*/ /* Counts the number of dimensions and the dim[] array for an array string. The * syntax for array input is C-like nested curly braces *----------------------------------------------------------------------------*/ int _ArrayCount(str, dim, typdelim) d175 5 a179 5 int nest_level = 0, i; int ndim = 0, temp[MAXDIM]; bool scanning_string = false; bool eoArray = false; char *q; d181 1 a181 2 for (i = 0; i < MAXDIM; temp[i] = dim[i++] = 0); q = str; d183 1 a183 1 if (strncmp (str, "{}", 2) == 0) return(0); d185 2 a186 1 while (eoArray != true) { d188 2 a189 4 while (!done) { switch (*q) { d191 1 a191 4 if (!scanning_string ) scanning_string = true; else scanning_string = false; d195 3 a197 3 temp[nest_level] = 0; nest_level++; } d201 5 a205 5 if (!ndim) ndim = nest_level; nest_level--; if (nest_level) temp[nest_level-1]++; if (nest_level == 0) eoArray = done = true; } d208 1 a208 1 if (!ndim) ndim = nest_level; d210 1 a210 1 done = true; d215 7 a221 6 temp[ndim-1]++; q++; if (!eoArray) while (isspace(*q)) q++; } for (i = 0; i < ndim; dim[i] = temp[i++]); return(ndim); d224 10 a233 5 /*-=-=-=-=-=-=-=-=--=-=-=-=-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-*/ /* parses the array string pointed by "arrayStr and converts it in the internal * format. inputproc() is the pointer to the function used for the conversion * The number of bytes used for storing the string is returned in "nbytes *-----------------------------------------------------------------------------*/ d235 2 a236 2 _ReadArrayString (arrayStr, nitems, inputproc, typelem, typdelim, typlen, typbyval, nbytes) int nitems, typlen, *nbytes; d239 1 a239 1 func_ptr inputproc; d242 1 a242 1 int i, dummy, nest_level = 0; d245 2 a246 8 *nbytes = 0; if (strcmp(arrayStr, "{}") == 0) { /* empty array, just return the total number of bytes */ if (typlen > 0) *nbytes = nitems * typlen; else elog(WARN, "array_in: Empty initialization not possible on variable length array elements"); return(NULL); } d248 3 a250 1 /* read array enclosed within {} */ d252 2 a253 1 q = p = arrayStr; d255 1 a255 2 for (i = 0; i < nitems; i++) { d257 1 a257 1 bool eoArray = false; d259 2 a260 4 while (!done) { switch (*q) { d266 1 a266 3 if (!scanning_string ) { scanning_string = true; d269 1 a269 5 break; } else { scanning_string = false; d271 1 a271 1 } d274 8 a281 1 if (!scanning_string) { p++; nest_level++;} d285 10 a294 8 nest_level--; if (nest_level == 0) { eoArray = done = true; if (i != nitems - 1) elog(WARN, "array_in: array dimensions don't match with array input"); } else *q = '\0'; } d297 6 a302 2 if (*q == typdelim && !scanning_string ) done = true; d305 2 a306 1 if (!done) q++; d308 3 a310 1 *q = '\0'; /* Put a null at the end of it */ d312 30 a341 18 if (!typbyval && !values[i]) { elog(NOTICE, "pass by reference array element is NULL, you may"); elog(WARN, "need to quote each individual element in the constant"); } p = ++q; /* p goes past 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; else for (i = 0, *nbytes = 0; i < nitems; *nbytes += LONGALIGN(* (int32 *) values[i]), i++); return((char *)values); d345 1 a345 1 /***************************************************************************** d347 1 d350 2 a351 2 _ReadLOArray(name, nbytes, fd) char *name; d353 2 d356 23 a378 1 char *saveName; d380 44 a423 19 while (isSpace(*name)) name++; saveName = name; while (!(isSpace(*name)) && (*name != '\0')) name++; *name = '\0'; name = palloc(strlen(saveName) + 2); strcpy (name, saveName); if (FilenameToOID(name) == InvalidObjectId) if ( (*fd = LOcreat (name, 0600, Unix)) < 0) elog(WARN, "Large object create failed"); pfree(name); *nbytes = strlen(saveName) + 2; return(saveName); } /*-=-=-=-==-=-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=--=-=-=-=-=-=-=-*/ _CopyArrayValues(typFlag, values, p, nitems, typlen, typbyval) bool typFlag, typbyval; d427 1 a427 1 int i; d429 8 a436 22 if (typFlag == false) { /* Regular array , so copy the actual array value */ if (values == NULL) { /* Empty array, just allocate the required space and zero it */ if (typlen > 0) bzero (p, nitems*typlen); return; } for (i = 0; i < nitems; i++) { int inc; inc = ArrayCastAndSet((char *)values[i], typbyval, typlen, p); p += inc; if (!typbyval) pfree((char *)values[i]); } pfree(values); } else { /* It is a large object, so just copy the name of the large object that holds the actual data */ strcpy(p, values); } d439 5 a443 2 /*******************************************************************************/ /* array_out() d450 9 d463 16 a478 6 if (ARR_IS_LO(v) == true) { char *p, *save_p; int nbytes, i; /* get a wide string to print to */ nbytes = strlen(ARR_DATA_PTR(v)) + 4; d480 1 a480 23 save_p = (char *) palloc(nbytes); sprintf(save_p, "%s ", ARR_DATA_PTR(v)); return (save_p); } else { int typlen; bool typbyval; char typdelim; ObjectId typoutput; ObjectId typelem; char *p, *q; char *retval; char **values; int nitems, nbytes, overall_length; int i, dummy; func_ptr outputproc; char delim[2]; int ndim, *dim, *lBound; system_cache_lookup(element_type, false, &typlen, &typbyval, d482 1 a482 1 fmgr_info(typoutput, & outputproc, &dummy); d484 11 a494 12 ndim = ARR_NDIM(v); dim = ARR_DIMS(v); getNitems(nitems, ndim, dim); if (nitems == 0) { char *emptyArray = palloc(3); emptyArray[0] = '{'; emptyArray[1] = '}'; emptyArray[2] = '\0'; return emptyArray; } d496 1 a496 1 p = ARR_DATA_PTR(v); d499 3 a501 6 for (i = 0; i < nitems; i++) { if (typbyval) { switch(typlen) { d514 1 a514 3 } else { d520 4 a523 4 /* * For the pair of double quotes */ overall_length += 2; d528 6 a533 1 p = (char *) palloc(overall_length + 3); d537 5 a541 3 for (i = 0; i < nitems; i++) { d543 18 a560 13 * Surround anything that is not passed by value in double quotes. * See above for more details. */ if (!typbyval) { strcat(p, "\""); strcat(p, values[i]); strcat(p, "\""); } else { strcat(p, values[i]); d562 2 a564 4 if (i != nitems - 1) strcat(p, delim); else strcat(p, "}"); pfree(values[i]); } a565 1 a566 1 } d568 5 a572 1 /****************************************************************************/ d582 7 a588 3 if (v == (ArrayType *) NULL) RETURN_NULL; nbytes = ARR_NDIM(v)*25; save_p = p = (char *) palloc(nbytes); d590 1 d595 2 d599 8 a606 3 /************************************************************************/ /* This routing takes an array and an index array and returns a pointer * to the referred element */ d608 1 a608 1 array_ref(array, n, indx, reftype, len, isNull) d611 1 a611 1 int reftype, len; d616 1 a616 1 char *retval; d618 10 a627 1 if (array == (ArrayType *) NULL) RETURN_NULL; d629 1 a629 1 lb = ARR_LBOUND(array); d631 1 a631 1 nbytes = (* (int32 *) array) - ARR_OVERHEAD(ndim); d636 1 a636 1 GetOffset(offset, n, dim, lb, indx); d638 3 a640 9 if (ARR_IS_LO(array)) { char * lo_name; int fd; /* We are assuming fixed element lengths here */ offset *= len; lo_name = (char *)ARR_DATA_PTR(array); if ((fd = LOopen(lo_name, O_RDONLY)) < 0) RETURN_NULL; d642 47 a688 38 if (LOlseek(fd, offset, L_SET) < 0) RETURN_NULL; v = (struct varlena *) LOread(fd, len); if (VARSIZE(v) - 4 < len) RETURN_NULL; (void) LOclose(fd); if (len < 0) return (Datum) v; return _ArrayCast((char *)VARDATA(v), reftype, len); } if (len > 0) { offset = offset * len; /* off the end of the array */ if (nbytes - offset < 1) RETURN_NULL; retval = ARR_DATA_PTR (array) + offset; return _ArrayCast(retval, reftype, len); } 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 -= LONGALIGN(* (int32 *) temp); temp += LONGALIGN(* (int32 *) temp); i++; } if (! done) RETURN_NULL; return (Datum) retval; } d691 6 a696 4 /************************************************************************/ /* 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. d707 3 a709 3 char *retval; ArrayType *newArr; int bytes, span[MAXDIM]; d711 3 a713 1 if (array == (ArrayType *) NULL) RETURN_NULL; d715 1 a715 1 lb = ARR_LBOUND(array); d717 1 a717 1 nbytes = (* (int32 *) array) - ARR_OVERHEAD(ndim); d722 1 a722 1 if (!SanityCheckInput(ndim, n, dim, lb, lowerIndx)) d725 67 a791 18 for (i = 0; i < n; i++) if (lowerIndx[i] > upperIndx[i]) elog(WARN, "lowerIndex cannot be larger than upperIndx"); get_range(n, span, lowerIndx, upperIndx); if (ARR_IS_LO(array)) { char * lo_name, * newname; int fd, newfd; if (len < 0) elog(WARN, "array_clip: array of variable length objects not supported"); lo_name = (char *)ARR_DATA_PTR(array); if ((fd = LOopen(lo_name, O_RDONLY)) < 0) RETURN_NULL; newname = _array_newLO(); _ReadLOArray(newname, &bytes, &newfd); bytes += ARR_OVERHEAD(n); newArr = (ArrayType *) palloc(bytes); d796 1 a796 22 strcpy(ARR_DATA_PTR(newArr), newname); _LOArrayRange(lowerIndx, upperIndx, len, fd, newfd, array, 1, isNull); (void) LOclose(fd); (void) LOclose(newfd); if (*isNull) { pfree(newArr); newArr = NULL;} return ((Datum) newArr); } if (len > 0) { getNitems(bytes, n, span); bytes = bytes*len + ARR_OVERHEAD(n); } else { bytes = _ArrayClipCount(lowerIndx, upperIndx, array); bytes += ARR_OVERHEAD(n); } newArr = (ArrayType *) palloc(bytes); bcopy(array, newArr, sizeof(ArrayType)); bcopy(&bytes, newArr, sizeof(int)); bcopy(span, ARR_DIMS(newArr), n*sizeof(int)); bcopy(lowerIndx, ARR_LBOUND(newArr), n*sizeof(int)); _ArrayRange(lowerIndx, upperIndx, len, ARR_DATA_PTR(newArr), array, 1); d800 8 a807 1 /********************************************************************/ d809 1 a809 1 array_set(array, n, indx, dataPtr, reftype, len, isNull) d814 1 a814 1 int reftype, len; d817 1 d819 12 a830 1 if (array == (ArrayType *) NULL) RETURN_NULL; d834 1 a834 1 nbytes = (* (int32 *) array) - ARR_OVERHEAD(ndim); d836 3 a838 2 if (!SanityCheckInput(ndim, n, dim, lb, indx)) return((char *)array); GetOffset(offset, n, dim, lb, indx); d841 21 a861 20 int fd; char * lo_name; struct varlena *v; /* We are assuming fixed element lengths here */ offset *= len; lo_name = ARR_DATA_PTR(array); if ((fd = LOopen(lo_name, O_WRONLY)) < 0) return((char *)array); if (LOlseek(fd, offset, L_SET) < 0) return((char *)array); v = (struct varlena *) palloc(len + 4); VARSIZE (v) = len + 4; ArrayCastAndSet(dataPtr, (bool) reftype, len, VARDATA(v)); n = LOwrite(fd, v); if (n < VARSIZE(v) - 4) RETURN_NULL; pfree(v); (void) LOclose(fd); return((char *)array); d863 2 a864 4 else { char *pos; if (len > 0) { offset = offset * len; d868 4 a871 22 } else { /* bool done = false; char *temp; int bytes = nbytes; temp = ARR_DATA_PTR (array); i = 0; while (bytes > 0 && !done) { if (i == offset) { pos = temp; done = true; } bytes -= LONGALIGN(* (int32 *) temp); temp += LONGALIGN(* (int32 *) temp); i++; } if (! done) return((char *)array); */ elog(WARN, "array_set: update of variable length fields not supported"); } ArrayCastAndSet(dataPtr, (bool) reftype, len, pos); } d875 8 a882 1 /*--------------------------------------------------------------------*/ d891 5 a895 4 if (array == (ArrayType *) NULL) RETURN_NULL; if (len < 0) elog(WARN, "array_assgn: assignment on arrays of variable length elements not supported"); d898 1 a898 1 lb = ARR_LBOUND(array); d901 4 a904 2 if (!SanityCheckInput(ndim, n, dim, lb, upperIndx)) RETURN_NULL; d906 3 a908 2 if (!SanityCheckInput(ndim, n, dim, lb, lowerIndx)) RETURN_NULL; d910 3 a912 7 for (i = 0; i < n; i++) if (lowerIndx[i] > upperIndx[i]) elog(WARN, "lowerIndex cannot be larger than upperIndx"); if (ARR_IS_LO(array)) { char * lo_name; int fd, newfd; d914 17 a930 17 lo_name = (char *)ARR_DATA_PTR(array); if ((fd = LOopen(lo_name, O_WRONLY)) < 0) RETURN_NULL; if (ARR_IS_LO(newArr)) { lo_name = (char *)ARR_DATA_PTR(newArr); if ((newfd = LOopen(lo_name, O_RDONLY)) < 0) RETURN_NULL; _LOArrayRange(lowerIndx, upperIndx, len, fd, newfd, array, 0, 1, isNull); (void) LOclose(newfd); } else _LOArrayRange(lowerIndx, upperIndx, len, fd, ARR_DATA_PTR(newArr), array, 0, 0, isNull); (void) LOclose(fd); return ((char *) array); } _ArrayRange(lowerIndx, upperIndx, len, ARR_DATA_PTR(newArr), array, 0); d933 7 a939 1 /***************************************************************************/ d943 4 a946 3 if ( *(int *)array1 != *(int *)array2 ) return (0); if ( strncmp(array1, array2, *(int *)array1)) return(0); return(1); d949 1 a949 1 /***************************UTILITIES***************************************/ d951 1 a951 3 system_cache_lookup(element_type, input, typlen, typbyval, typdelim, typelem, proc) d966 1 a966 2 if (!HeapTupleIsValid(typeTuple)) { d976 1 a976 2 if (input) { d978 1 a978 3 } else { d986 3 a988 3 char *value; bool byval; int len; d992 10 a1001 11 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; d1005 1 a1005 1 } d1014 1 a1014 1 int inc; d1016 15 a1030 14 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; } a1031 1 else bcopy(src, dest, typlen); d1033 1 a1033 3 } else { d1035 1 a1035 1 inc = (LONGALIGN(* (int32 *) src)); d1037 1 a1037 1 return(inc); d1039 21 d1066 1 a1066 1 if (n != ndim) elog(WARN, "array dimension does not match"); d1069 2 a1070 2 return(0); return(1); d1081 1 a1081 1 char *srcPtr; d1084 2 a1085 2 lb = ARR_LBOUND(array); srcPtr = ARR_DATA_PTR(array); for (i = 0; i < n; st[i] -= lb[i], endp[i] -= lb[i], i++); d1087 2 a1088 2 tuple2linear(n, st_pos, st, prod); srcPtr = array_seek(srcPtr, bsize, st_pos); d1095 4 a1098 2 if (from) inc = array_read(destPtr, bsize, 1, srcPtr); else inc = array_read(srcPtr, bsize, 1, destPtr); d1111 2 a1112 2 int count = 0; char *ptr; d1118 2 a1119 2 tuple2linear(n, st_pos, st, prod); ptr = array_seek(ptr, -1, st_pos); d1129 1 a1129 1 return(count); d1138 1 a1138 1 int i; d1140 5 a1144 4 if (eltsize > 0) return(ptr + eltsize*nitems); for (i = 0; i < nitems; i++) ptr += LONGALIGN(* (int *) ptr); return(ptr); d1151 1 a1151 1 int i, inc, tmp; d1153 5 a1157 5 if (eltsize > 0) { bcopy(srcptr, destptr, eltsize*nitems); return(eltsize*nitems); } for (i = inc = 0; i < nitems; i++) { d1159 1 a1159 1 bcopy(srcptr, destptr, tmp); d1162 40 a1201 3 inc += tmp; } return(inc); d1203 1 d1205 2 a1206 2 _LOArrayRange(st, endp, bsize, srcfd, destfd, array, from, isSrcLO, isNull) int st[], endp[], bsize, from, isSrcLO; d1220 4 a1223 3 tuple2linear(n, st_pos, st, prod); offset = st_pos*bsize; if (LOlseek(srcfd, offset, L_SET) < 0) RETURN_NULL; d1227 3 a1229 2 for (i = n-1, inc = bsize; i >= 0; inc *= span[i--]) if (dist[i]) break; d1232 7 a1238 6 offset += (dist[j]*bsize); if (LOlseek(srcfd, offset, L_SET) < 0) RETURN_NULL; if (from) tmp = _LOtransfer(&destfd, inc, 1, &srcfd, isSrcLO); else tmp = _LOtransfer(&srcfd, inc, 1, &destfd, isSrcLO); if ( tmp < inc ) RETURN_NULL; offset += inc; d1243 3 a1245 2 _LOtransfer(destfd, size, nitems, srcfd, isSrcLO) int *destfd, *srcfd, size, nitems, isSrcLO; d1247 26 a1272 16 struct varlena *v; int tmp, inc; char buf[8000]; inc = nitems*size; if (isSrcLO) { v = (struct varlena *) LOread(*srcfd, inc); if (VARSIZE(v) - 4 < inc) return(-1); } else { v = (struct varlena *)buf; VARSIZE(v) = inc + sizeof(int); bcopy (*srcfd, VARDATA(v), inc); *srcfd += inc; } tmp = LOwrite(*destfd, v); return(tmp); d1290 1 a1290 1 while (isSpace(*s)) d1296 3 a1298 1 } else while (*s != '\0') s++; d1302 1 a1302 1 retval = array_set(array, i, indx, dataPtr, &isNull); a1307 22 /*----------------------------------------------------------------------------- generates the tuple that is lexicographically one greater than the current n-tuple in "curr", with the restriction that the i-th element of "curr" is less than the i-th element of "span". RETURNS 0 if no next tuple exists 1 otherwise -----------------------------------------------------------------------------*/ next_tuple(n, curr, span) int n, span[], curr[]; { int i; if (!n) return(-1); curr[n-1] = (curr[n-1]+1)%span[n-1]; for (i = n-1; i*(!curr[i]); i--) curr[i-1] = (curr[i-1]+1)%span[i-1]; if (i) return(i); if (curr[0]) return(0); return(-1); } /**********************************************************************/ d1309 3 a1311 1 _array_newLO() d1314 7 a1320 2 p = (char *) palloc(30); sprintf(p, "/ArryClip.%d", newoid()); @ 1.21 log @removed references to utils/fmgr.h and parser/parse.h @ text @d1 1 a1 1 /* d6 1 a6 1 * RcsId("$Header: /home2/aoki/postgres/src/backend/utils/adt/RCS/arrayfuncs.c,v 1.20 1992/12/15 02:32:06 aoki Exp aoki $"); d12 1 d16 1 d21 1 d23 12 a34 67 /* * Function prototypes - contained in this file as no one outside should * be calling these except the function manager. */ int array_count ARGS((char *string , char delimiter )); int system_cache_lookup ARGS(( ObjectId element_type , Boolean input , int *typlen , bool *typbyval , char *typdelim , ObjectId *typelem , ObjectId *proc )); /* * array_count - counts the number of elements in an array. * XXX since this code only counts items when it seems a delimiter, * it is unable to return "1" .. so assume that if we've seen a * string that there's actually an array item somewhere. * (hence single items *must* be quoted.) FIX ME CORRECTLY. */ int array_count(string, delimiter) char *string; char delimiter; { int i = 1, nelems = 0; bool scanning_string = false, seen_string = false; int nest_level = 1; while (nest_level >= 1) { switch (string[i]) { case '\\': i++; break; case '{': if (!scanning_string) nest_level++; break; case '}': if (!scanning_string) nest_level--; break; case '\"': scanning_string = !scanning_string; seen_string = true; break; case 0: elog(WARN, "array constant is missing a closing bracket"); break; default: if (!scanning_string && nest_level == 1 && string[i] == delimiter) { nelems++; } break; } i++; } d36 1 a36 13 /* * account for last element in list. * * Careful! If the array string is "{}" there is no 'last element' */ return(((nelems > 0 || seen_string) ? (nelems + 1) : 0)); } /* * array_in - takes an array surrounded by {...} and returns it in * VARLENA format: */ a39 1 d46 1 a46 1 bool typbyval; a50 1 char **values; d54 3 a56 6 char *retval; bool scanning_string = false; if (charTypid == InvalidObjectId) { HeapTuple tup; a57 5 tup = (HeapTuple)SearchSysCacheTuple(TYPNAME, "char"); if ((charTypid = tup->t_oid) == InvalidObjectId) elog(WARN, "type lookup on char failed"); } d64 1 d66 38 a103 12 if (string[0] != '{') { if (element_type == charTypid) { /* * this is a hack to allow char arrays to have a { in the * first position. Of course now \{ can never be the first * two characters, but what else can we do? */ string = (*string == '\\' && *(string+1) == '{') ? &string[1] : string; return (char *)textin(string); d105 10 a114 4 else elog(WARN, "array_in: malformed array constant"); } else d116 4 a119 1 strcpy(string_save, string); d122 42 a163 3 if ((nitems = array_count(string, typdelim)) == 0) { char *emptyArray = palloc(sizeof(int32)); d165 37 a201 2 * (int32 *) emptyArray = sizeof(int32); return emptyArray; d203 3 d207 16 a222 1 values = (char **) palloc(nitems * sizeof(char *)); d224 7 a230 1 p = q = string_save; d232 3 a234 1 p++; q++; /* get past leading '{' */ a237 1 int nest_level = 0; d239 1 a239 1 bool eoArray = false; d250 1 a250 1 if (!scanning_string && nest_level == 0) d257 1 a257 1 else if (nest_level == 0) d264 1 a264 1 if (!scanning_string) nest_level++; d267 9 a275 6 if (nest_level == 0 && !scanning_string) { done = true; eoArray = true; } else if (!scanning_string) nest_level--; d278 2 a279 2 if (*q == typdelim && !scanning_string && nest_level == 0) done = true; d299 7 d307 25 a331 11 if (typlen > 0) { nbytes = nitems * typlen + sizeof(int32); } else { for (i = 0, nbytes = 0; i < nitems; nbytes += LONGALIGN(* (int32 *) values[i]), i++); nbytes += sizeof(int32); } d333 7 a339 2 retval = (char *) palloc(nbytes); p = retval + 4; d341 2 a342 1 bcopy(&nbytes, retval, sizeof(int4)); d344 11 a354 18 for (i = 0; i < nitems; i++) { if (typlen > 0) { if (typbyval) { char oneByte; short twoBytes; switch(typlen) { case 1: *p = DatumGetChar(values[i]); break; case 2: * (int16 *) p = DatumGetInt16(values[i]); break; case 4: * (int32 *) p = (int32)values[i]; break; d356 7 a362 18 } else bcopy(values[i], p, typlen); p += typlen; } else { int len; len = LONGALIGN(* (int32 *) values[i]); bcopy(values[i], p, * (int32 *) values[i]); p += len; } if (!typbyval) pfree(values[i]); } pfree(string_save); pfree((char *)values); return(retval); d365 3 d369 7 a375 1 array_out(items, element_type) d377 8 a384 2 char *items; ObjectId element_type; d386 3 a388 4 { /* * statics so we don't do excessive system cache lookups. */ d390 2 a391 1 int typlen; d397 1 a397 1 char *p; d400 1 a400 1 int32 nitems, nbytes, overall_length; d404 1 d406 1 a406 1 system_cache_lookup(element_type, false, &typlen, &typbyval, d408 1 a408 2 fmgr_info(typoutput, & outputproc, &dummy); d410 3 a412 7 /* * It's an array of fixed-length things (either fixed-length arrays * or non-array objects. We can compute the number of items just by * dividing the number of bytes in the blob of memory by the length * of each element. */ d414 1 a414 1 if (typlen > 0) d416 5 a420 1 nitems = (* (int32 *) items - 4)/ typlen; a421 1 else d423 2 a424 28 /* * It's an array of variable length objects. We have to manually walk * through each variable length element to count the number of elements. */ { nbytes = (* (int32 *) items) - sizeof(int32); nitems = 0; p = items + sizeof(int32); while (nbytes != 0) { nbytes -= LONGALIGN(* (int32 *) p); p += LONGALIGN(* (int32 *) p); nitems++; } } items += sizeof(int32); if (nitems == 0) { char *emptyArray = palloc(3); emptyArray[0] = '{'; emptyArray[1] = '}'; emptyArray[2] = '\0'; return emptyArray; } a425 2 overall_length = 0; d433 1 a433 1 values[i] = (*outputproc) (*items, typelem); d436 1 a436 1 values[i] = (*outputproc) (* (int16 *) items, typelem); d440 1 a440 1 values[i] = (*outputproc) (* (int32 *) items, typelem); d443 1 a443 1 items += typlen; d447 1 a447 1 values[i] = (*outputproc) (items, typelem); d449 1 a449 1 items += typlen; d451 1 a451 8 items += LONGALIGN(* (int32 *) items); /* * For the pair of double quotes */ overall_length += 2; } overall_length += strlen(values[i]); d453 1 a453 5 * So that the mapping between input and output functions is preserved * in the case of array_out(array_in(string)), we have to put double * quotes around strings that look like text strings. To be sure, and * since it will not break anything, we will put double quotes around * anything that is not passed by value. d455 3 a457 2 if (!typbyval) overall_length += 2; d490 246 d738 62 d837 282 @ 1.20 log @allow array_in to read one-item arrays.. @ text @d6 1 a6 1 * RcsId("$Header: /usr/local/dev/postgres/mastertree/newconf/RCS/arrayfuncs.c,v 1.19 1992/08/07 02:31:23 mer Exp $"); d17 1 a17 1 #include "utils/fmgr.h" @ 1.19 log @fix for handling arrays of 0 elements @ text @d6 1 a6 1 * RcsId("$Header: /private/mer/pg/src/utils/adt/RCS/arrayfuncs.c,v 1.18 1992/05/06 05:09:55 mer Exp mer $"); d39 4 d53 1 a53 1 bool scanning_string = false; d71 1 d94 1 a94 1 return(((nelems > 0) ? (nelems + 1) : 0)); @ 1.18 log @fix byte ordering bug. @ text @d6 1 a6 1 * RcsId("$Header: /u/mer/pg/src/utils/adt/RCS/arrayfuncs.c,v 1.17 1992/04/03 07:31:58 mer Exp $"); d85 2 d89 1 a89 1 return(nelems + 1); d155 7 a161 1 nitems = array_count(string, typdelim); d351 8 @ 1.17 log @check to be sure we're not scanning a string when we find the delimiter char @ text @d6 1 a6 1 * RcsId("$Header: /users/mer/pg/src/utils/adt/RCS/arrayfuncs.c,v 1.16 1992/04/03 01:06:24 mer Exp mer $"); d209 5 d246 13 a258 1 bcopy(&values[i], p, typlen); @ 1.16 log @we're writing beyond the allocated string boundary - a no no @ text @d6 1 a6 1 * RcsId("$Header: /users/mer/pg/src/utils/adt/RCS/arrayfuncs.c,v 1.15 1992/03/16 19:09:47 mer Exp mer $"); d201 2 a202 1 if (*q == typdelim && nest_level == 0) done = true; @ 1.15 log @oops, don't use a function from the parser module @ text @d6 1 a6 1 * RcsId("$Header: /users/mer/pg/src/utils/adt/RCS/arrayfuncs.c,v 1.14 1992/03/16 05:21:53 mer Exp mer $"); d354 4 @ 1.14 log @hack to allow char arrays to have { as the first character @ text @d6 1 a6 1 * RcsId("$Header: /users/mer/pg/src/utils/adt/RCS/arrayfuncs.c,v 1.13 1992/03/16 04:52:29 mer Exp mer $"); d120 1 a120 1 tup = (HeapTuple)type("char"); @ 1.13 log @doctor up character arrays a bit. @ text @d6 1 a6 1 * RcsId("$Header: /users/mer/pg/src/utils/adt/RCS/arrayfuncs.c,v 1.12 1992/02/17 13:47:42 mer Exp mer $"); d68 3 d135 8 d144 1 @ 1.12 log @oops, forgot to include ctype.h which the sparc requires for isspace() @ text @d6 1 a6 1 * RcsId("$Header: RCS/arrayfuncs.c,v 1.11 92/02/15 22:54:45 mer Exp Locker: mer $"); d99 1 d113 9 d131 4 a134 1 elog(WARN, "array_in: malformatted array constant"); @ 1.11 log @fix space problem (added extra spaces before strings) @ text @d6 1 a6 1 * RcsId("$Header: /users/mer/pg/src/utils/adt/RCS/arrayfuncs.c,v 1.10 1991/12/15 02:00:59 glass Exp mer $"); d9 1 @ 1.10 log @fmgr cleanups @ text @d6 1 a6 1 * RcsId("$Header: ./utils/adt/RCS/arrayfuncs.c,v 1.9 91/11/09 01:45:54 mer Exp Locker: glass $"); d139 1 d168 1 d170 2 d182 7 a188 1 p = q + 1; q++; /* p goes past q */ d285 1 a285 1 nbytes = * (int32 *) items - sizeof(int32); @ 1.9 log @add prototypes and fix up prototype warnings @ text @d6 1 a6 1 * RcsId("$Header: /users/mer/postgres/src/utils/adt/RCS/arrayfuncs.c,v 1.8 1991/04/11 01:37:01 kemnitz Exp mer $"); d105 1 a105 1 FmgrFunction inputproc; d247 1 a247 1 FmgrFunction outputproc; @ 1.8 log @Now works for arrays of arrays using array_in and array_out. @ text @d6 1 a6 1 * RcsId("$Header: RCS/arrayfuncs.c,v 1.7 91/04/04 18:26:16 kemnitz Exp Locker: kemnitz $"); d20 17 d221 1 a221 1 pfree(values); d359 1 a359 1 pfree(values); @ 1.7 log @Now work for strings and backquoted stuff. @ text @d6 1 a6 1 * RcsId("$Header: RCS/arrayfuncs.c,v 1.6 91/03/30 17:27:44 kemnitz Exp Locker: kemnitz $"); d30 1 a30 2 int i = 0, nelems = 0; bool end_on_bracket = false; d32 1 d34 1 a34 1 if (string[0] == '{') d36 1 a36 7 end_on_bracket = true; i++; } while (string[i] != (end_on_bracket ? '}' : '\0')) { if (string[i] == '\\') d38 20 a57 1 i++; a58 12 else if (string[i] == delimiter && !scanning_string) { nelems++; } else if (scanning_string && string[i] == '\"') { scanning_string = false; } else if (!scanning_string && string[i] == '\"') { scanning_string = true; } d81 5 a85 7 static ObjectId element_type_save = 0; static int typlen; static bool typbyval; static char typdelim; static ObjectId typinput; static ObjectId typelem; d94 2 a95 6 if (element_type_save != element_type) { system_cache_lookup(element_type, true, &typlen, &typbyval, &typdelim, &typelem, &typinput); element_type_save = element_type; } a98 2 nitems = array_count(string, typdelim); d103 1 a103 1 sprintf(string_save, "{%s}", string); d110 2 d120 4 a123 1 while (*q != typdelim && !scanning_string && *q != '}') d125 1 a125 1 if (*q == '\\') d127 29 a155 2 /* Crunch the string on top of the backslash. */ for (r = q; *r != '}'; r++) *r = *(r+1); d157 1 a157 12 else if (*q == '\"' && !scanning_string) { scanning_string = true; while (*p != '\"') p++; p++; /* get p past first doublequote */ } else if (*q == '\"' && scanning_string) { scanning_string = false; *q = '\0'; } q++; d219 5 a223 6 static ObjectId element_type_save = 0; static int typlen; static bool typbyval; static char typdelim; static ObjectId typoutput; static ObjectId typelem; d233 2 a234 6 if (element_type != element_type_save) { system_cache_lookup(element_type, false, &typlen, &typbyval, &typdelim, &typelem, &typoutput); element_type_save = element_type; } @ 1.6 log @fixed a bug. @ text @d6 1 a6 1 * RcsId("$Header: RCS/arrayfuncs.c,v 1.5 91/03/28 13:52:34 kemnitz Exp Locker: kemnitz $"); d20 49 d87 1 a87 1 char *string_save, *p, *q; d93 1 a94 10 string_save = (char *) palloc(strlen(string) + 3); if (*string != '{') { sprintf(string_save, "{%s}", string); } else { strcpy(string_save, string); } d104 5 a108 1 for (i = 0, nitems = 0; string_save[i] != '}'; i++) d110 1 a110 1 if (string_save[i] == typdelim) nitems++; d112 4 d117 1 a117 1 nitems++; /* account for last item in list */ a118 2 values = (char **) palloc(nitems * sizeof(char *)); d123 1 a123 1 for (i = 0; i < nitems - 1; i++) d125 20 a144 1 while (*q != typdelim) q++; /* Get to end of next string */ a149 5 while (*q != '}') q++; *q = '\0'; values[nitems - 1] = (*inputproc) (p, typelem); d294 10 d311 1 a311 1 for (i = 0; i < nitems - 1; i++) d313 17 a329 2 strcat(p, values[i]); strcat(p, delim); a332 4 strcat(p, values[nitems - 1]); strcat(p, "}"); pfree(values[nitems - 1]); a336 6 char * string_in(a1, a2) {} char * string_out(a1, a2) {} @ 1.5 log @when array_in is called for the first time, the string is not enclosed in {}. @ text @d6 1 a6 1 * RcsId("$Header: RCS/arrayfuncs.c,v 1.4 91/03/27 02:32:21 kemnitz Exp Locker: kemnitz $"); d36 1 d46 1 a46 1 if (*string != '{') d48 1 a48 1 sprintf(string_save, "{%s}", string); d50 1 a50 1 else d57 2 a58 2 system_cache_lookup(element_type, true, &typlen, &typbyval, &typdelim, &typinput); d81 1 a81 1 values[i] = (*inputproc) (p); /* p points to head of string we want */ d88 1 a88 1 values[nitems - 1] = (*inputproc) (p); d150 1 d162 2 a163 2 system_cache_lookup(element_type, false, &typlen, &typbyval, &typdelim, &typoutput); d213 1 a213 1 values[i] = (*outputproc) (*items); d216 1 a216 1 values[i] = (*outputproc) (* (int16 *) items); d220 1 a220 1 values[i] = (*outputproc) (* (int32 *) items); d227 1 a227 1 values[i] = (*outputproc) (items); d263 2 a264 1 system_cache_lookup(element_type, input, typlen, typbyval, typdelim, proc) d271 1 d287 4 a290 3 *typlen = typeStruct->typlen; *typbyval = typeStruct->typbyval; *typdelim = typeStruct->typdelim; @ 1.4 log @LONGALIGN'ed variable length arrays of things. @ text @d6 1 a6 1 * RcsId("$Header: RCS/arrayfuncs.c,v 1.3 91/03/27 02:12:55 kemnitz Exp Locker: kemnitz $"); d44 9 a52 2 string_save = (char *) palloc(strlen(string) + 1); strcpy(string_save, string); @ 1.3 log @Various bug fixes. @ text @d6 1 a6 1 * RcsId("$Header: RCS/arrayfuncs.c,v 1.2 91/03/26 12:49:24 kemnitz Exp Locker: kemnitz $"); d10 2 d14 1 d90 1 a90 1 nbytes += * (int32 *) values[i++]); d115 2 a116 2 len = * (int32 *) values[i]; bcopy(values[i], p, len); d186 2 a187 2 nbytes -= * (int32 *) p; p += * (int32 *) p; d222 1 a222 1 items += * (int32 *) items; @ 1.2 log @Fixed compilation errors. @ text @d6 1 a6 1 * RcsId("$Header: ../src/utils/adt/RCS/arrayfuncs.c,v 1.1 91/03/26 11:04:04 kemnitz Exp Locker: kemnitz $"); d60 1 a60 1 values = (char **) palloc(nitems); d79 1 a79 1 if (typlen != 0) d83 7 a89 7 else { for (i = 0, nbytes = 0; i < nitems; i++, nbytes += * (int32 *) values[i]); nbytes += sizeof(int32); } d91 2 a92 2 retval = (char *) palloc(nbytes); p = retval; d94 1 a94 1 bcopy(retval, &nbytes, sizeof(int4)); d96 15 a110 10 for (i = 0; i < nitems; i++) { if (typlen != 0) { bcopy(retval, p, typlen); p += typlen; } else { int len; d112 9 a120 9 len = * (int32 *) p; bcopy(retval, p, len); p += len; } if (!typbyval) pfree(values[i]); } pfree(string_save); pfree(values); return(retval); d165 1 a165 1 if (typlen != 0) d167 1 a167 1 nitems = * (int32 *) items / typlen; d196 1 a196 4 values[i] = (*outputproc) (items); overall_length += strlen(values[i]); if (typlen != 0) d198 13 d215 5 a219 1 items += * (int32 *) items; d221 1 @ 1.1 log @Initial revision @ text @d6 1 a6 1 * RcsId("$Header: RCS/arrayfuncs.c,v 1.6 91/02/28 20:55:53 mao Exp $"); d10 2 d14 1 d51 1 a51 1 fmgr_info(typoutput, & inputproc, &dummy); d53 1 a53 1 for (i = 0; nitems = 0; string_save[i] != '}'; i++) d121 1 a121 1 char *items d233 2 a234 2 ObjectId type; boolean input; @