diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2000-07-22 03:34:43 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2000-07-22 03:34:43 +0000 |
commit | d0e17e211230d37f26843711115864a87d0eae18 (patch) | |
tree | b039e4879d7faeb1ddfc33f6051af4b21fbc3ce4 /src/backend/utils/adt/arrayfuncs.c | |
parent | ec37ea1cc1356f1a0b7dad1d9e4933e50bea583f (diff) | |
download | postgresql-d0e17e211230d37f26843711115864a87d0eae18.tar.gz postgresql-d0e17e211230d37f26843711115864a87d0eae18.zip |
Arrays are toastable. (At least if you initdb, which I didn't force.)
Remove a bunch of crufty code for large-object-based arrays, which is
superseded by TOAST and likely hasn't worked in a long time anyway.
Clean up array code a little, and in particular eliminate its habit
of scribbling on the input array (ie, modifying the input tuple :-().
Diffstat (limited to 'src/backend/utils/adt/arrayfuncs.c')
-rw-r--r-- | src/backend/utils/adt/arrayfuncs.c | 1061 |
1 files changed, 273 insertions, 788 deletions
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c index 907082a7268..b4bc71f349a 100644 --- a/src/backend/utils/adt/arrayfuncs.c +++ b/src/backend/utils/adt/arrayfuncs.c @@ -1,14 +1,14 @@ /*------------------------------------------------------------------------- * * arrayfuncs.c - * Special functions for arrays. + * Support functions for arrays. * * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.61 2000/07/17 03:05:17 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.62 2000/07/22 03:34:43 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,15 +19,15 @@ #include "catalog/catalog.h" #include "catalog/pg_type.h" -#include "libpq/be-fsstubs.h" -#include "libpq/libpq-fs.h" -#include "storage/fd.h" #include "utils/array.h" #include "utils/memutils.h" #include "utils/syscache.h" #define ASSGN "=" +#define RETURN_NULL(type) do { *isNull = true; return (type) 0; } while (0) + + /* * An array has the following internal structure: * <nbytes> - total number of bytes @@ -36,41 +36,30 @@ * <dim> - size of each array axis * <dim_lower> - lower boundary of each dimension * <actual data> - whatever is the stored data + * The actual data starts on a MAXALIGN boundary. */ -static int _ArrayCount(char *str, int *dim, int typdelim); +static int ArrayCount(char *str, int *dim, int typdelim); static Datum *ReadArrayStr(char *arrayStr, int nitems, int ndim, int *dim, FmgrInfo *inputproc, Oid typelem, int32 typmod, char typdelim, int typlen, bool typbyval, char typalign, int *nbytes); -#ifdef LOARRAY -static char *_ReadLOArray(char *str, int *nbytes, int *fd, bool *chunkFlag, - int ndim, int *dim, int baseSize); -#endif static void CopyArrayEls(char *p, Datum *values, int nitems, bool typbyval, int typlen, char typalign, bool freedata); 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); - -#ifdef LOARRAY -static char *_AdvanceBy1word(char *str, char **word); - -#endif -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 Datum ArrayCast(char *value, bool byval, int len); +static void ArrayClipCopy(int *st, int *endp, int bsize, char *destPtr, + ArrayType *array, bool from); +static int ArrayClipCount(int *st, int *endp, ArrayType *array); static int ArrayCastAndSet(Datum src, bool typbyval, int typlen, char *dest); -static int SanityCheckInput(int ndim, int n, int *dim, int *lb, int *indx); +static bool SanityCheckInput(int ndim, int n, int *dim, int *lb, int *indx); static int array_read(char *destptr, int eltsize, int nitems, char *srcptr); static char *array_seek(char *ptr, int eltsize, int nitems); + /*--------------------------------------------------------------------- * array_in : * converts an array from the external format in "string" to @@ -153,8 +142,9 @@ array_in(PG_FUNCTION_ARGS) { if (*p == '{') { - ndim = _ArrayCount(p, dim, typdelim); - for (i = 0; i < ndim; lBound[i++] = 1); + ndim = ArrayCount(p, dim, typdelim); + for (i = 0; i < ndim; i++) + lBound[i] = 1; } else elog(ERROR, "array_in: Need to specify dimension"); @@ -179,71 +169,46 @@ array_in(PG_FUNCTION_ARGS) printf(") for %s\n", string); #endif - nitems = getNitems(ndim, dim); + nitems = ArrayGetNItems(ndim, dim); if (nitems == 0) { retval = (ArrayType *) palloc(sizeof(ArrayType)); MemSet(retval, 0, sizeof(ArrayType)); - *(int32 *) retval = sizeof(ArrayType); + retval->size = sizeof(ArrayType); PG_RETURN_ARRAYTYPE_P(retval); } - if (*p == '{') - { - /* array not a large object */ - dataPtr = ReadArrayStr(p, nitems, ndim, dim, &inputproc, typelem, - typmod, typdelim, typlen, typbyval, typalign, - &nbytes); - nbytes += ARR_OVERHEAD(ndim); - retval = (ArrayType *) palloc(nbytes); - MemSet(retval, 0, nbytes); - retval->size = nbytes; - retval->ndim = ndim; - SET_LO_FLAG(false, retval); - memcpy((char *) ARR_DIMS(retval), (char *) dim, - ndim * sizeof(int)); - memcpy((char *) ARR_LBOUND(retval), (char *) lBound, - ndim * sizeof(int)); - - CopyArrayEls(ARR_DATA_PTR(retval), dataPtr, nitems, - typbyval, typlen, typalign, true); - pfree(dataPtr); - } - 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); - retval->size = nbytes; - retval->ndim = ndim; - 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(ERROR, "large object arrays not supported"); - PG_RETURN_NULL(); - } + if (*p != '{') + elog(ERROR, "array_in: missing left brace"); + + dataPtr = ReadArrayStr(p, nitems, ndim, dim, &inputproc, typelem, + typmod, typdelim, typlen, typbyval, typalign, + &nbytes); + nbytes += ARR_OVERHEAD(ndim); + retval = (ArrayType *) palloc(nbytes); + MemSet(retval, 0, nbytes); + retval->size = nbytes; + retval->ndim = ndim; + memcpy((char *) ARR_DIMS(retval), (char *) dim, + ndim * sizeof(int)); + memcpy((char *) ARR_LBOUND(retval), (char *) lBound, + ndim * sizeof(int)); + + CopyArrayEls(ARR_DATA_PTR(retval), dataPtr, nitems, + typbyval, typlen, typalign, true); + pfree(dataPtr); pfree(string_save); PG_RETURN_ARRAYTYPE_P(retval); } /*----------------------------------------------------------------------------- - * _ArrayCount + * 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) +ArrayCount(char *str, int *dim, int typdelim) { int nest_level = 0, i; @@ -411,7 +376,7 @@ ReadArrayStr(char *arrayStr, if (!scanning_string) { if (i == -1) - i = tuple2linear(ndim, indx, prod); + i = ArrayGetOffset0(ndim, indx, prod); nest_level--; if (nest_level == 0) eoArray = done = true; @@ -426,7 +391,7 @@ ReadArrayStr(char *arrayStr, if (*q == typdelim && !scanning_string) { if (i == -1) - i = tuple2linear(ndim, indx, prod); + i = ArrayGetOffset0(ndim, indx, prod); done = true; indx[ndim - 1]++; } @@ -491,79 +456,6 @@ ReadArrayStr(char *arrayStr, } -/*---------------------------------------------------------------------------- - * Read data about an array to be stored as a large object - *---------------------------------------------------------------------------- - */ -#ifdef LOARRAY -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(ERROR, "array_in: access pattern file required"); - str = _AdvanceBy1word(str, &accessfile); - } - else if (!strcmp(word, "-noreorg")) - { - if (str == NULL) - elog(ERROR, "array_in: chunk file required"); - str = _AdvanceBy1word(str, &chunkfile); - } - else - elog(ERROR, "usage: <input file> -chunk DEFAULT/<access pattern file> -invert/-native [-noreorg <chunk file>]"); - } - - if (inputfile == NULL) - elog(ERROR, "array_in: missing file name"); - lobjId = DatumGetObjectId(DirectFunctionCall1(lo_creat, - Int32GetDatum(0))); - *fd = DatumGetInt32(DirectFunctionCall2(lo_open, - ObjectIdGetDatum(lobjId), - Int32GetDatum(INV_READ))); - if (*fd < 0) - elog(ERROR, "Large object create failed"); - retStr = inputfile; - *nbytes = strlen(retStr) + 2; - - if (accessfile) - { - FILE *afd; - - if ((afd = AllocateFile(accessfile, PG_BINARY_R)) == NULL) - elog(ERROR, "unable to open access pattern file"); - *chunkFlag = true; - retStr = _ChunkArray(*fd, afd, ndim, dim, baseSize, nbytes, - chunkfile); - FreeFile(afd); - } - return retStr; -} - -#endif - /*---------- * Copy data into an array object from a temporary array of Datums. * @@ -634,34 +526,13 @@ array_out(PG_FUNCTION_ARGS) int ndim, *dim; - if (ARR_IS_LO(v) == true) - { - text *p; - int plen, - nbytes; - - p = (text *) DatumGetPointer(DirectFunctionCall1(array_dims, - PointerGetDatum(v))); - plen = VARSIZE(p) - VARHDRSZ; - - /* get a wide string to print to */ - nbytes = strlen(ARR_DATA_PTR(v)) + strlen(ASSGN) + plen + 1; - retval = (char *) palloc(nbytes); - - memcpy(retval, VARDATA(p), plen); - strcpy(retval + plen, ASSGN); - strcat(retval, ARR_DATA_PTR(v)); - pfree(p); - PG_RETURN_CSTRING(retval); - } - system_cache_lookup(element_type, false, &typlen, &typbyval, &typdelim, &typelem, &typoutput, &typalign); fmgr_info(typoutput, &outputproc); sprintf(delim, "%c", typdelim); ndim = ARR_NDIM(v); dim = ARR_DIMS(v); - nitems = getNitems(ndim, dim); + nitems = ArrayGetNItems(ndim, dim); if (nitems == 0) { @@ -814,7 +685,6 @@ array_dims(PG_FUNCTION_ARGS) */ result = (text *) palloc(nbytes + VARHDRSZ); - MemSet(result, 0, nbytes + VARHDRSZ); p = VARDATA(result); dimv = ARR_DIMS(v); @@ -846,143 +716,87 @@ array_ref(ArrayType *array, int arraylen, bool *isNull) { - int i, - ndim, + int ndim, *dim, *lb, - offset, - nbytes; - struct varlena *v = NULL; - Datum result; - char *retval; + offset; + char *retptr; if (array == (ArrayType *) NULL) RETURN_NULL(Datum); + if (arraylen > 0) { - /* - * fixed length arrays -- these are assumed to be 1-d + * fixed-length arrays -- these are assumed to be 1-d, 0-based */ - if (indx[0] * elmlen > arraylen) - elog(ERROR, "array_ref: array bound exceeded"); - retval = (char *) array + indx[0] * elmlen; - return _ArrayCast(retval, elmbyval, elmlen); + if (nSubscripts != 1) + RETURN_NULL(Datum); + if (indx[0] < 0 || indx[0] * elmlen >= arraylen) + RETURN_NULL(Datum); + retptr = (char *) array + indx[0] * elmlen; + return ArrayCast(retptr, elmbyval, elmlen); } + + /* detoast input if necessary */ + array = DatumGetArrayTypeP(PointerGetDatum(array)); + + ndim = ARR_NDIM(array); dim = ARR_DIMS(array); lb = ARR_LBOUND(array); - ndim = ARR_NDIM(array); - nbytes = (*(int32 *) array) - ARR_OVERHEAD(ndim); if (!SanityCheckInput(ndim, nSubscripts, dim, lb, indx)) RETURN_NULL(Datum); - offset = GetOffset(nSubscripts, dim, lb, indx); - - if (ARR_IS_LO(array)) - { - char *lo_name; - int fd = 0; - - /* 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(Datum); -#endif - if (ARR_IS_CHUNKED(array)) - v = _ReadChunkArray1El(indx, elmlen, fd, array, isNull); - else - { - if (DatumGetInt32(DirectFunctionCall3(lo_lseek, - Int32GetDatum(fd), - Int32GetDatum(offset), - Int32GetDatum(SEEK_SET))) < 0) - RETURN_NULL(Datum); -#ifdef LOARRAY - v = (struct varlena *) - DatumGetPointer(DirectFunctionCall2(loread, - Int32GetDatum(fd), - Int32GetDatum(elmlen))); -#endif - } - if (*isNull) - RETURN_NULL(Datum); - if (VARSIZE(v) - VARHDRSZ < elmlen) - RETURN_NULL(Datum); - DirectFunctionCall1(lo_close, Int32GetDatum(fd)); - result = _ArrayCast((char *) VARDATA(v), elmbyval, elmlen); - if (! elmbyval) - { /* not by value */ - char *tempdata = palloc(elmlen); - - memcpy(tempdata, DatumGetPointer(result), elmlen); - result = PointerGetDatum(tempdata); - } - pfree(v); - return result; - } + offset = ArrayGetOffset(nSubscripts, dim, lb, indx); - if (elmlen > 0) - { - offset = offset * elmlen; - /* off the end of the array */ - if (nbytes - offset < 1) - RETURN_NULL(Datum); - retval = ARR_DATA_PTR(array) + offset; - return _ArrayCast(retval, elmbyval, elmlen); - } - else - { - int bytes = nbytes; + retptr = array_seek(ARR_DATA_PTR(array), elmlen, offset); - retval = ARR_DATA_PTR(array); - i = 0; - while (bytes > 0) - { - if (i == offset) - return PointerGetDatum(retval); - bytes -= INTALIGN(*(int32 *) retval); - retval += INTALIGN(*(int32 *) retval); - i++; - } - RETURN_NULL(Datum); - } + return ArrayCast(retptr, elmbyval, elmlen); } /*----------------------------------------------------------------------------- - * array_clip : - * This routine takes an array and a range of indices (upperIndex and + * array_get_slice : + * 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. *----------------------------------------------------------------------------- */ ArrayType * -array_clip(ArrayType *array, - int nSubscripts, - int *upperIndx, - int *lowerIndx, - bool elmbyval, - int elmlen, - bool *isNull) +array_get_slice(ArrayType *array, + int nSubscripts, + int *upperIndx, + int *lowerIndx, + bool elmbyval, + int elmlen, + int arraylen, + bool *isNull) { int i, ndim, *dim, - *lb, - nbytes; + *lb; ArrayType *newArr; int bytes, span[MAXDIM]; - /* timer_start(); */ if (array == (ArrayType *) NULL) RETURN_NULL(ArrayType *); + + if (arraylen > 0) + { + /* + * fixed-length arrays -- no can do slice... + */ + elog(ERROR, "Slices of fixed-length arrays not implemented"); + } + + /* detoast input if necessary */ + array = DatumGetArrayTypeP(PointerGetDatum(array)); + + ndim = ARR_NDIM(array); dim = ARR_DIMS(array); lb = ARR_LBOUND(array); - ndim = ARR_NDIM(array); - nbytes = (*(int32 *) array) - ARR_OVERHEAD(ndim); if (!SanityCheckInput(ndim, nSubscripts, dim, lb, upperIndx) || !SanityCheckInput(ndim, nSubscripts, dim, lb, lowerIndx)) @@ -990,116 +804,40 @@ array_clip(ArrayType *array, for (i = 0; i < nSubscripts; i++) if (lowerIndx[i] > upperIndx[i]) - elog(ERROR, "lowerIndex cannot be larger than upperIndx"); - mda_get_range(nSubscripts, span, lowerIndx, upperIndx); - - if (ARR_IS_LO(array)) - { -#ifdef LOARRAY - char *lo_name; - -#endif - char *newname = NULL; - int fd = 0, - newfd = 0, - isDestLO = true, - rsize; - - if (elmlen < 0) - elog(ERROR, "array_clip: array of variable length objects not implemented"); -#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(ArrayType *); - newname = _array_newLO(&newfd, Unix); -#endif - bytes = strlen(newname) + 1 + ARR_OVERHEAD(nSubscripts); - newArr = (ArrayType *) palloc(bytes); - newArr->size = bytes; - newArr->ndim = array->ndim; - newArr->flags = array->flags; - memcpy(ARR_DIMS(newArr), span, nSubscripts * sizeof(int)); - memcpy(ARR_LBOUND(newArr), lowerIndx, nSubscripts * sizeof(int)); - strcpy(ARR_DATA_PTR(newArr), newname); - - rsize = compute_size(lowerIndx, upperIndx, nSubscripts, elmlen); - if (rsize < BLCKSZ) - { - char *buff; - rsize += VARHDRSZ; - buff = palloc(rsize); - if (buff) - isDestLO = false; - if (ARR_IS_CHUNKED(array)) - { - _ReadChunkArray(lowerIndx, upperIndx, elmlen, fd, &(buff[VARHDRSZ]), - array, 0, isNull); - } - else - { - _ReadArray(lowerIndx, upperIndx, elmlen, fd, (int) &(buff[VARHDRSZ]), - array, - 0, isNull); - } - memmove(buff, &rsize, VARHDRSZ); -#ifdef LOARRAY - if (!*isNull) - bytes = DatumGetInt32(DirectFunctionCall2(lowrite, - Int32GetDatum(newfd), - PointerGetDatum(buff))); -#endif - pfree(buff); - } - if (isDestLO) - { - if (ARR_IS_CHUNKED(array)) - { - _ReadChunkArray(lowerIndx, upperIndx, elmlen, fd, (char *) newfd, array, - 1, isNull); - } - else - _ReadArray(lowerIndx, upperIndx, elmlen, fd, newfd, array, 1, isNull); - } -#ifdef LOARRAY - LOclose(fd); - LOclose(newfd); -#endif - if (*isNull) - { - pfree(newArr); - newArr = NULL; - } - /* timer_end(); */ - return newArr; - } + mda_get_range(nSubscripts, span, lowerIndx, upperIndx); if (elmlen > 0) - { - bytes = getNitems(nSubscripts, span); - bytes = bytes * elmlen + ARR_OVERHEAD(nSubscripts); - } + bytes = ArrayGetNItems(nSubscripts, span) * elmlen; else - { - bytes = _ArrayClipCount(lowerIndx, upperIndx, array); - bytes += ARR_OVERHEAD(nSubscripts); - } + bytes = ArrayClipCount(lowerIndx, upperIndx, array); + bytes += ARR_OVERHEAD(nSubscripts); + newArr = (ArrayType *) palloc(bytes); newArr->size = bytes; newArr->ndim = array->ndim; newArr->flags = array->flags; memcpy(ARR_DIMS(newArr), span, nSubscripts * sizeof(int)); memcpy(ARR_LBOUND(newArr), lowerIndx, nSubscripts * sizeof(int)); - _ArrayRange(lowerIndx, upperIndx, elmlen, ARR_DATA_PTR(newArr), array, 1); + ArrayClipCopy(lowerIndx, upperIndx, elmlen, ARR_DATA_PTR(newArr), + array, true); + return newArr; } /*----------------------------------------------------------------------------- - * array_set : + * array_set : * This routine sets the value of an array location (specified by * an index array) to a new value specified by "dataValue". * result : - * returns a pointer to the modified array. + * A new array is returned, just like the old except for the one + * modified entry. + * + * NOTE: For assignments, we throw an error for silly subscripts etc, + * rather than returning a NULL as the fetch operations do. The reasoning + * is that returning a NULL would cause the user's whole array to be replaced + * with NULL, which will probably not make him happy. *----------------------------------------------------------------------------- */ ArrayType * @@ -1115,194 +853,154 @@ array_set(ArrayType *array, int ndim, *dim, *lb, - offset, - nbytes; - char *pos; + offset; + ArrayType *newarray; + char *elt_ptr; + int oldsize, + newsize, + oldlen, + newlen, + lth0, + lth1, + lth2; if (array == (ArrayType *) NULL) RETURN_NULL(ArrayType *); + if (arraylen > 0) { - /* - * fixed length arrays -- these are assumed to be 1-d + * fixed-length arrays -- these are assumed to be 1-d, 0-based */ - if (indx[0] * elmlen > arraylen) - elog(ERROR, "array_ref: array bound exceeded"); - pos = (char *) array + indx[0] * elmlen; - ArrayCastAndSet(dataValue, elmbyval, elmlen, pos); - return array; + if (nSubscripts != 1) + elog(ERROR, "Invalid array subscripts"); + if (indx[0] < 0 || indx[0] * elmlen >= arraylen) + elog(ERROR, "Invalid array subscripts"); + newarray = (ArrayType *) palloc(arraylen); + memcpy(newarray, array, arraylen); + elt_ptr = (char *) newarray + indx[0] * elmlen; + ArrayCastAndSet(dataValue, elmbyval, elmlen, elt_ptr); + return newarray; } + + /* detoast input if necessary */ + array = DatumGetArrayTypeP(PointerGetDatum(array)); + + ndim = ARR_NDIM(array); dim = ARR_DIMS(array); lb = ARR_LBOUND(array); - ndim = ARR_NDIM(array); - nbytes = (*(int32 *) array) - ARR_OVERHEAD(ndim); if (!SanityCheckInput(ndim, nSubscripts, dim, lb, indx)) - { - elog(ERROR, "array_set: array bound exceeded"); - return array; - } - offset = GetOffset(nSubscripts, dim, lb, indx); + elog(ERROR, "Invalid array subscripts"); - if (ARR_IS_LO(array)) - { - int fd = 0; - struct varlena *v; + offset = ArrayGetOffset(nSubscripts, dim, lb, indx); - /* We are assuming fixed element lengths here */ - offset *= elmlen; -#ifdef LOARRAY - char *lo_name; + elt_ptr = array_seek(ARR_DATA_PTR(array), elmlen, offset); - lo_name = ARR_DATA_PTR(array); - if ((fd = LOopen(lo_name, ARR_IS_INV(array) ? INV_WRITE : O_WRONLY)) < 0) - return array; -#endif - if (DatumGetInt32(DirectFunctionCall3(lo_lseek, - Int32GetDatum(fd), - Int32GetDatum(offset), - Int32GetDatum(SEEK_SET))) < 0) - return array; - v = (struct varlena *) palloc(elmlen + VARHDRSZ); - VARATT_SIZEP(v) = elmlen + VARHDRSZ; - ArrayCastAndSet(dataValue, elmbyval, elmlen, VARDATA(v)); -#ifdef LOARRAY - if (DatumGetInt32(DirectFunctionCall2(lowrite, - Int32GetDatum(fd), - PointerGetDatum(v))) - != elmlen) - RETURN_NULL(ArrayType *); -#endif - pfree(v); - DirectFunctionCall1(lo_close, Int32GetDatum(fd)); - return array; - } if (elmlen > 0) { - offset = offset * elmlen; - /* off the end of the array */ - if (nbytes - offset < 1) - return array; - pos = ARR_DATA_PTR(array) + offset; + oldlen = newlen = elmlen; } else { - ArrayType *newarray; - char *elt_ptr; - int oldsize, - newsize, - oldlen, - newlen, - lth0, - lth1, - lth2; - - elt_ptr = array_seek(ARR_DATA_PTR(array), -1, offset); + /* varlena type */ oldlen = INTALIGN(*(int32 *) elt_ptr); newlen = INTALIGN(*(int32 *) DatumGetPointer(dataValue)); - - if (oldlen == newlen) - { - /* new element with same size, overwrite old data */ - ArrayCastAndSet(dataValue, elmbyval, elmlen, elt_ptr); - return array; - } - - /* new element with different size, reallocate the array */ - oldsize = array->size; - lth0 = ARR_OVERHEAD(nSubscripts); - lth1 = (int) (elt_ptr - ARR_DATA_PTR(array)); - lth2 = (int) (oldsize - lth0 - lth1 - oldlen); - newsize = lth0 + lth1 + newlen + lth2; - - newarray = (ArrayType *) palloc(newsize); - memmove((char *) newarray, (char *) array, lth0 + lth1); - newarray->size = newsize; - newlen = ArrayCastAndSet(dataValue, elmbyval, elmlen, - (char *) newarray + lth0 + lth1); - memmove((char *) newarray + lth0 + lth1 + newlen, - (char *) array + lth0 + lth1 + oldlen, lth2); - - /* ??? who should free this storage ??? */ - return newarray; } - ArrayCastAndSet(dataValue, elmbyval, elmlen, pos); - return array; + + oldsize = ARR_SIZE(array); + lth0 = ARR_OVERHEAD(ndim); + lth1 = (int) (elt_ptr - ARR_DATA_PTR(array)); + lth2 = (int) (oldsize - lth0 - lth1 - oldlen); + newsize = lth0 + lth1 + newlen + lth2; + + newarray = (ArrayType *) palloc(newsize); + memcpy((char *) newarray, (char *) array, lth0 + lth1); + memcpy((char *) newarray + lth0 + lth1 + newlen, + (char *) array + lth0 + lth1 + oldlen, lth2); + newarray->size = newsize; + newlen = ArrayCastAndSet(dataValue, elmbyval, elmlen, + (char *) newarray + lth0 + lth1); + + return newarray; } /*---------------------------------------------------------------------------- - * array_assgn : + * array_set_slice : * 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. + * A new array is returned, just like the old except for the + * modified range. + * + * NOTE: For assignments, we throw an error for silly subscripts etc, + * rather than returning a NULL as the fetch operations do. The reasoning + * is that returning a NULL would cause the user's whole array to be replaced + * with NULL, which will probably not make him happy. *---------------------------------------------------------------------------- */ ArrayType * -array_assgn(ArrayType *array, - int nSubscripts, - int *upperIndx, - int *lowerIndx, - ArrayType *newArr, - bool elmbyval, - int elmlen, - bool *isNull) +array_set_slice(ArrayType *array, + int nSubscripts, + int *upperIndx, + int *lowerIndx, + ArrayType *srcArray, + bool elmbyval, + int elmlen, + int arraylen, + bool *isNull) { int i, ndim, *dim, *lb; + int span[MAXDIM]; if (array == (ArrayType *) NULL) RETURN_NULL(ArrayType *); + if (srcArray == (ArrayType *) NULL) + RETURN_NULL(ArrayType *); + + if (arraylen > 0) + { + /* + * fixed-length arrays -- no can do slice... + */ + elog(ERROR, "Updates on slices of fixed-length arrays not implemented"); + } + + /* detoast array, making sure we get an overwritable copy */ + array = DatumGetArrayTypePCopy(PointerGetDatum(array)); + + /* detoast source array if necessary */ + srcArray = DatumGetArrayTypeP(PointerGetDatum(srcArray)); + if (elmlen < 0) - elog(ERROR, "array_assgn: updates on arrays of variable length elements not implemented"); + elog(ERROR, "Updates on slices of arrays of variable length elements not implemented"); + ndim = ARR_NDIM(array); dim = ARR_DIMS(array); lb = ARR_LBOUND(array); - ndim = ARR_NDIM(array); if (!SanityCheckInput(ndim, nSubscripts, dim, lb, upperIndx) || !SanityCheckInput(ndim, nSubscripts, dim, lb, lowerIndx)) - RETURN_NULL(ArrayType *); + elog(ERROR, "Invalid array subscripts"); for (i = 0; i < nSubscripts; i++) if (lowerIndx[i] > upperIndx[i]) - elog(ERROR, "lowerIndex larger than upperIndx"); + elog(ERROR, "Invalid array subscripts"); - if (ARR_IS_LO(array)) - { - int fd = 0, - newfd = 0; + /* make sure source array has enough entries */ + mda_get_range(ndim, span, lowerIndx, upperIndx); -#ifdef LOARRAY - char *lo_name; + if (ArrayGetNItems(ndim, span) > + ArrayGetNItems(ARR_NDIM(srcArray), ARR_DIMS(srcArray))) + elog(ERROR, "Source array too small"); + + ArrayClipCopy(lowerIndx, upperIndx, elmlen, ARR_DATA_PTR(srcArray), + array, false); - lo_name = (char *) ARR_DATA_PTR(array); - if ((fd = LOopen(lo_name, ARR_IS_INV(array) ? INV_WRITE : O_WRONLY)) < 0) - return 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 array; -#endif - _LOArrayRange(lowerIndx, upperIndx, elmlen, fd, newfd, array, 1, isNull); - DirectFunctionCall1(lo_close, Int32GetDatum(newfd)); - } - else - { - _LOArrayRange(lowerIndx, upperIndx, elmlen, fd, (int) ARR_DATA_PTR(newArr), - array, 0, isNull); - } - DirectFunctionCall1(lo_close, Int32GetDatum(fd)); - return array; - } - _ArrayRange(lowerIndx, upperIndx, elmlen, ARR_DATA_PTR(newArr), array, 0); return array; } @@ -1337,7 +1035,7 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType) ArrayType *v; ArrayType *result; Datum *values; - char *elt; + Datum elt; int *dim; int ndim; int nitems; @@ -1360,13 +1058,9 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType) elog(ERROR, "array_map: null input array"); v = PG_GETARG_ARRAYTYPE_P(0); - /* Large objects not yet supported */ - if (ARR_IS_LO(v) == true) - elog(ERROR, "array_map: large objects not supported"); - ndim = ARR_NDIM(v); dim = ARR_DIMS(v); - nitems = getNitems(ndim, dim); + nitems = ArrayGetNItems(ndim, dim); /* Check for empty array */ if (nitems <= 0) @@ -1380,7 +1074,6 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType) /* Allocate temporary array for new values */ values = (Datum *) palloc(nitems * sizeof(Datum)); - MemSet(values, 0, nitems * sizeof(Datum)); /* Loop over source data */ s = (char *) ARR_DATA_PTR(v); @@ -1392,22 +1085,25 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType) switch (inp_typlen) { case 1: - elt = (char *) ((int) (*(char *) s)); + elt = CharGetDatum(*s); break; case 2: - elt = (char *) ((int) (*(int16 *) s)); + elt = Int16GetDatum(*(int16 *) s); break; - case 3: case 4: + elt = Int32GetDatum(*(int32 *) s); + break; default: - elt = (char *) (*(int32 *) s); + elog(ERROR, "array_map: unsupported byval length %d", + inp_typlen); + elt = 0; /* keep compiler quiet */ break; } s += inp_typlen; } else { - elt = s; + elt = PointerGetDatum(s); if (inp_typlen > 0) s += inp_typlen; else @@ -1421,7 +1117,7 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType) * whether fn() is strict. Would need to do more work here * to support arrays containing nulls, too. */ - fcinfo->arg[0] = (Datum) elt; + fcinfo->arg[0] = elt; fcinfo->argnull[0] = false; fcinfo->isnull = false; values[i] = FunctionCallInvoke(fcinfo); @@ -1524,7 +1220,7 @@ deconstruct_array(ArrayType *array, char *p; int i; - nelems = getNitems(ARR_NDIM(array), ARR_DIMS(array)); + nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array)); if (nelems <= 0) { *elemsp = NULL; @@ -1570,6 +1266,8 @@ deconstruct_array(ArrayType *array, * compares two arrays for equality * result : * returns true if the arrays are equal, false otherwise. + * + * XXX bitwise equality is pretty bogus ... *----------------------------------------------------------------------------- */ Datum @@ -1577,17 +1275,25 @@ array_eq(PG_FUNCTION_ARGS) { ArrayType *array1 = PG_GETARG_ARRAYTYPE_P(0); ArrayType *array2 = PG_GETARG_ARRAYTYPE_P(1); + bool result = true; + + if (ARR_SIZE(array1) != ARR_SIZE(array2)) + result = false; + else if (memcmp(array1, array2, ARR_SIZE(array1)) != 0) + result = false; - if (*(int32 *) array1 != *(int32 *) array2) - PG_RETURN_BOOL(false); - if (memcmp(array1, array2, *(int32 *) array1) != 0) - PG_RETURN_BOOL(false); - PG_RETURN_BOOL(true); + /* Avoid leaking memory when handed toasted input. */ + PG_FREE_IF_COPY(array1, 0); + PG_FREE_IF_COPY(array2, 1); + + PG_RETURN_BOOL(result); } + /***************************************************************************/ /******************| Support Routines |*****************/ /***************************************************************************/ + static void system_cache_lookup(Oid element_type, bool input, @@ -1620,28 +1326,26 @@ system_cache_lookup(Oid element_type, *proc = typeStruct->typoutput; } +/* Fetch array value at pointer, converted correctly to a Datum */ static Datum -_ArrayCast(char *value, bool byval, int len) +ArrayCast(char *value, bool byval, int len) { - if (byval) + if (! byval) + return PointerGetDatum(value); + + switch (len) { - switch (len) - { - case 1: - return (Datum) *value; - case 2: - return (Datum) *(int16 *) value; - case 3: - case 4: - return (Datum) *(int32 *) value; - default: - elog(ERROR, "array_ref: byval and elt len > 4!"); - break; - } + case 1: + return CharGetDatum(*value); + case 2: + return Int16GetDatum(*(int16 *) value); + case 4: + return Int32GetDatum(*(int32 *) value); + default: + elog(ERROR, "ArrayCast: unsupported byval length %d", len); + break; } - else - return (Datum) value; - return 0; + return 0; /* keep compiler quiet */ } /* @@ -1673,7 +1377,8 @@ ArrayCastAndSet(Datum src, *(int32 *) dest = DatumGetInt32(src); break; default: - elog(ERROR, "ArrayCastAndSet: unexpected typlen"); + elog(ERROR, "ArrayCastAndSet: unsupported byval length %d", + typlen); break; } /* For by-val types, assume no alignment padding is needed */ @@ -1693,55 +1398,32 @@ ArrayCastAndSet(Datum src, /* XXX WRONG: should use MAXALIGN or type's alignment requirement */ inc = INTALIGN(VARSIZE(DatumGetPointer(src))); } - return inc; -} -#ifdef LOARRAY -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; + return inc; } -#endif - -static int +/* Do Sanity check on input subscripting info */ +static bool SanityCheckInput(int ndim, int n, int *dim, int *lb, int *indx) { int i; - /* Do Sanity check on input */ - if (n != ndim) - return 0; + if (n != ndim || ndim <= 0 || ndim > MAXDIM) + return false; for (i = 0; i < ndim; i++) if ((lb[i] > indx[i]) || (indx[i] >= (dim[i] + lb[i]))) - return 0; - return 1; + return false; + return true; } +/* Copy an array slice into or out of an array */ static void -_ArrayRange(int *st, - int *endp, - int bsize, - char *destPtr, - ArrayType *array, - int from) +ArrayClipCopy(int *st, + int *endp, + int bsize, + char *destPtr, + ArrayType *array, + bool from) { int n, *dim, @@ -1759,16 +1441,14 @@ _ArrayRange(int *st, 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++); + st_pos = ArrayGetOffset(n, dim, lb, st); + srcPtr = array_seek(ARR_DATA_PTR(array), bsize, st_pos); 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; + for (i = 0; i < n; i++) + indx[i] = 0; + j = n - 1; do { srcPtr = array_seek(srcPtr, bsize, dist[j]); @@ -1778,11 +1458,12 @@ _ArrayRange(int *st, inc = array_read(srcPtr, bsize, 1, destPtr); destPtr += inc; srcPtr += inc; - } while ((j = next_tuple(i + 1, indx, span)) != -1); + } while ((j = mda_next_tuple(n, indx, span)) != -1); } +/* Compute space needed for an array slice of varlena items */ static int -_ArrayClipCount(int *stI, int *endpI, ArrayType *array) +ArrayClipCount(int *st, int *endp, ArrayType *array) { int n, *dim, @@ -1794,34 +1475,32 @@ _ArrayClipCount(int *stI, int *endpI, ArrayType *array) indx[MAXDIM]; int i, j, - inc, - st[MAXDIM], - endp[MAXDIM]; + inc; int count = 0; char *ptr; 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++); + st_pos = ArrayGetOffset(n, dim, lb, st); + ptr = array_seek(ARR_DATA_PTR(array), -1, st_pos); 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; + for (i = 0; i < n; i++) + indx[i] = 0; + 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); + } while ((j = mda_next_tuple(n, indx, span)) != -1); return count; } +/* Advance over nitems array elements */ static char * array_seek(char *ptr, int eltsize, int nitems) { @@ -1834,6 +1513,7 @@ array_seek(char *ptr, int eltsize, int nitems) return ptr; } +/* Copy nitems array elements from srcptr to destptr */ static int array_read(char *destptr, int eltsize, int nitems, char *srcptr) { @@ -1846,7 +1526,8 @@ array_read(char *destptr, int eltsize, int nitems, char *srcptr) memmove(destptr, srcptr, eltsize * nitems); return eltsize * nitems; } - for (i = inc = 0; i < nitems; i++) + inc = 0; + for (i = 0; i < nitems; i++) { tmp = (INTALIGN(*(int32 *) srcptr)); memmove(destptr, srcptr, tmp); @@ -1856,199 +1537,3 @@ array_read(char *destptr, int eltsize, int nitems, char *srcptr) } 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 (DatumGetInt32(DirectFunctionCall3(lo_lseek, - Int32GetDatum(srcfd), - Int32GetDatum(offset), - Int32GetDatum(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 (DatumGetInt32(DirectFunctionCall3(lo_lseek, - Int32GetDatum(srcfd), - Int32GetDatum(offset), - Int32GetDatum(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 (DatumGetInt32(DirectFunctionCall3(lo_lseek, - Int32GetDatum(srcfd), - Int32GetDatum(offset), - Int32GetDatum(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 (DatumGetInt32(DirectFunctionCall3(lo_lseek, - Int32GetDatum(srcfd), - Int32GetDatum(offset), - Int32GetDatum(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) -#if !defined(min) -#define min(a, b) (a < b ? a : b) -#endif - struct varlena *v = NULL; - 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 *) - DatumGetPointer(DirectFunctionCall2(loread, - Int32GetDatum((int32) *srcfd), - Int32GetDatum(inc))); - if (VARSIZE(v) - VARHDRSZ < inc) - { - pfree(v); - return -1; - } - tmp += DatumGetInt32(DirectFunctionCall2(lowrite, - Int32GetDatum((int32) *destfd), - PointerGetDatum(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.%u", newoid()); - strcpy(saveName, p); -#ifdef LOARRAY - if ((*fd = LOcreat(saveName, 0600, flag)) < 0) - elog(ERROR, "Large object create failed"); -#endif - return p; -} |