diff --git a/contrib/array/array_iterator.c b/contrib/array/array_iterator.c index 447d5c6443..c480f7dfc7 100644 --- a/contrib/array/array_iterator.c +++ b/contrib/array/array_iterator.c @@ -47,15 +47,18 @@ array_iterator(Oid elemtype, Oid proc, int and, ArrayType *array, Datum value) FmgrInfo finfo; /* Sanity checks */ - if ((array == (ArrayType *) NULL) - || (ARR_IS_LO(array) == true)) + if (array == (ArrayType *) NULL) { /* elog(NOTICE, "array_iterator: array is null"); */ return (0); } + + /* detoast input if necessary */ + array = DatumGetArrayTypeP(PointerGetDatum(array)); + ndim = ARR_NDIM(array); dim = ARR_DIMS(array); - nitems = getNitems(ndim, dim); + nitems = ArrayGetNItems(ndim, dim); if (nitems == 0) { /* elog(NOTICE, "array_iterator: nitems = 0"); */ diff --git a/src/backend/commands/define.c b/src/backend/commands/define.c index b90ef61a3b..cf31e5edb1 100644 --- a/src/backend/commands/define.c +++ b/src/backend/commands/define.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.45 2000/07/17 03:04:44 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.46 2000/07/22 03:34:26 tgl Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -691,10 +691,10 @@ DefineType(char *typeName, List *parameters) "array_in", /* receive procedure */ "array_out", /* send procedure */ typeName, /* element type name */ - defaultValue, /* default type value */ + NULL, /* never a default type value */ false, /* never passed by value */ - alignment, - 'p'); /* ARRAY doesn't support TOAST yet */ + alignment, /* NB: must be 'i' or 'd' for arrays... */ + 'x'); /* ARRAY is always toastable */ pfree(shadow_type); } diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index 48cd8aa169..1aeb07a7a9 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.74 2000/07/17 03:04:51 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.75 2000/07/22 03:34:27 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -67,9 +67,15 @@ static Datum ExecMakeFunctionResult(Node *node, List *arguments, /* * ExecEvalArrayRef * - * This function takes an ArrayRef and returns a Const Node if it - * is an array reference or returns the changed Array Node if it is - * an array assignment. + * This function takes an ArrayRef and returns the extracted Datum + * if it's a simple reference, or the modified array value if it's + * an array assignment (read array element insertion). + * + * NOTE: we deliberately refrain from applying DatumGetArrayTypeP() here, + * even though that might seem natural, because this code needs to support + * both varlena arrays and fixed-length array types. DatumGetArrayTypeP() + * only works for the varlena kind. The routines we call in arrayfuncs.c + * have to know the difference (that's what they need refattrlength for). */ static Datum ExecEvalArrayRef(ArrayRef *arrayRef, @@ -77,7 +83,8 @@ ExecEvalArrayRef(ArrayRef *arrayRef, bool *isNull, bool *isDone) { - ArrayType *array_scanner; + ArrayType *array_source; + ArrayType *resultArray; List *elt; int i = 0, j = 0; @@ -90,7 +97,7 @@ ExecEvalArrayRef(ArrayRef *arrayRef, if (arrayRef->refexpr != NULL) { - array_scanner = (ArrayType *) + array_source = (ArrayType *) DatumGetPointer(ExecEvalExpr(arrayRef->refexpr, econtext, isNull, @@ -110,7 +117,7 @@ ExecEvalArrayRef(ArrayRef *arrayRef, * the INSERT column list. This is a kluge, but it's not real * clear what the semantics ought to be... */ - array_scanner = NULL; + array_source = NULL; } foreach(elt, arrayRef->refupperindexpr) @@ -162,43 +169,45 @@ ExecEvalArrayRef(ArrayRef *arrayRef, if (*isNull) return (Datum) NULL; - if (array_scanner == NULL) + if (array_source == NULL) return sourceData; /* XXX do something else? */ - /* - * XXX shouldn't we copy the array value before modifying it?? - * - * Or perhaps these array routines should deliver a modified copy - * instead of changing the source in-place. - */ if (lIndex == NULL) - return PointerGetDatum(array_set(array_scanner, i, - upper.indx, - sourceData, - arrayRef->refelembyval, - arrayRef->refelemlength, - arrayRef->refattrlength, - isNull)); - return PointerGetDatum(array_assgn(array_scanner, i, - upper.indx, lower.indx, - (ArrayType *) DatumGetPointer(sourceData), - arrayRef->refelembyval, - arrayRef->refelemlength, - isNull)); + resultArray = array_set(array_source, i, + upper.indx, + sourceData, + arrayRef->refelembyval, + arrayRef->refelemlength, + arrayRef->refattrlength, + isNull); + else + resultArray = array_set_slice(array_source, i, + upper.indx, lower.indx, + (ArrayType *) DatumGetPointer(sourceData), + arrayRef->refelembyval, + arrayRef->refelemlength, + arrayRef->refattrlength, + isNull); + return PointerGetDatum(resultArray); } if (lIndex == NULL) - return array_ref(array_scanner, i, + return array_ref(array_source, i, upper.indx, arrayRef->refelembyval, arrayRef->refelemlength, arrayRef->refattrlength, isNull); - return PointerGetDatum(array_clip(array_scanner, i, + else + { + resultArray = array_get_slice(array_source, i, upper.indx, lower.indx, arrayRef->refelembyval, arrayRef->refelemlength, - isNull)); + arrayRef->refattrlength, + isNull); + return PointerGetDatum(resultArray); + } } diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile index ba39ab0300..0f42d93aad 100644 --- a/src/backend/utils/adt/Makefile +++ b/src/backend/utils/adt/Makefile @@ -1,7 +1,7 @@ # # Makefile for utils/adt # -# $Header: /cvsroot/pgsql/src/backend/utils/adt/Makefile,v 1.39 2000/07/13 16:07:14 petere Exp $ +# $Header: /cvsroot/pgsql/src/backend/utils/adt/Makefile,v 1.40 2000/07/22 03:34:43 tgl Exp $ # subdir = src/backend/utils/adt @@ -15,7 +15,7 @@ CFLAGS+= -mieee endif endif -OBJS = acl.o arrayfuncs.o arrayutils.o bool.o cash.o char.o chunk.o \ +OBJS = acl.o arrayfuncs.o arrayutils.o bool.o cash.o char.o \ date.o datetime.o datum.o filename.o float.o format_type.o \ geo_ops.o geo_selfuncs.o int.o int8.o like.o lztext.o \ misc.o nabstime.o name.o not_in.o numeric.o numutils.o \ diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c index 907082a726..b4bc71f349 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: * - total number of bytes @@ -36,41 +36,30 @@ * - size of each array axis * - lower boundary of each dimension * - 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)); + if (*p != '{') + elog(ERROR, "array_in: missing left brace"); - CopyArrayEls(ARR_DATA_PTR(retval), dataPtr, nitems, - typbyval, typlen, typalign, true); - pfree(dataPtr); - } - else - { -#ifdef LOARRAY - int dummy, - bytes; - bool chunked = false; + 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)); - 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(); - } + 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: -chunk DEFAULT/ -invert/-native [-noreorg ]"); - } - - 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); + offset = ArrayGetOffset(nSubscripts, dim, lb, indx); - if (ARR_IS_LO(array)) - { - char *lo_name; - int fd = 0; + retptr = array_seek(ARR_DATA_PTR(array), elmlen, offset); - /* 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; - } - - 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; - - 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"); + RETURN_NULL(ArrayType *); + 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; - } - 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 (elmlen < 0) - elog(ERROR, "array_assgn: updates on arrays of variable length elements not implemented"); + 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, "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 (*(int32 *) array1 != *(int32 *) array2) - PG_RETURN_BOOL(false); - if (memcmp(array1, array2, *(int32 *) array1) != 0) - PG_RETURN_BOOL(false); - PG_RETURN_BOOL(true); + if (ARR_SIZE(array1) != ARR_SIZE(array2)) + result = false; + else if (memcmp(array1, array2, ARR_SIZE(array1)) != 0) + result = false; + + /* 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; -} - -#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; -} diff --git a/src/backend/utils/adt/arrayutils.c b/src/backend/utils/adt/arrayutils.c index 3293cecc96..d103d8b885 100644 --- a/src/backend/utils/adt/arrayutils.c +++ b/src/backend/utils/adt/arrayutils.c @@ -8,61 +8,62 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayutils.c,v 1.10 2000/01/26 05:57:12 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayutils.c,v 1.11 2000/07/22 03:34:43 tgl Exp $ * *------------------------------------------------------------------------- */ -#define WEAK_C_OPTIMIZER - #include "postgres.h" + #include "utils/array.h" + + +/* Convert subscript list into linear element number (from 0) */ int -GetOffset(int n, int *dim, int *lb, int *indx) +ArrayGetOffset(int n, int *dim, int *lb, int *indx) { int i, - scale, - offset; + scale = 1, + offset = 0; - for (i = n - 1, scale = 1, offset = 0; i >= 0; scale *= dim[i--]) + for (i = n - 1; i >= 0; i--) + { offset += (indx[i] - lb[i]) * scale; + scale *= dim[i]; + } return offset; } +/* Same, but subscripts are assumed 0-based, and use a scale array + * instead of raw dimension data (see mda_get_prod to create scale array) + */ int -getNitems(int n, int *a) +ArrayGetOffset0(int n, int *tup, int *scale) +{ + int i, + lin = 0; + + for (i = 0; i < n; i++) + lin += tup[i] * scale[i]; + return lin; +} + +/* Convert array dimensions into number of elements */ +int +ArrayGetNItems(int n, int *a) { int i, ret; - for (i = 0, ret = 1; i < n; ret *= a[i++]); - if (n == 0) - ret = 0; + if (n <= 0) + return 0; + ret = 1; + for (i = 0; i < n; i++) + ret *= a[i]; return ret; } -int -compute_size(int *st, int *endp, int n, int base) -{ - int i, - ret; - - for (i = 0, ret = base; i < n; i++) - ret *= (endp[i] - st[i] + 1); - return ret; -} - -void -mda_get_offset_values(int n, int *dist, int *PC, int *span) -{ - int i, - j; - - for (j = n - 2, dist[n - 1] = 0; j >= 0; j--) - for (i = j + 1, dist[j] = PC[j] - 1; i < n; - dist[j] -= (span[i] - 1) * PC[i], i++); -} - +/* Compute ranges (sub-array dimensions) for an array slice */ void mda_get_range(int n, int *span, int *st, int *endp) { @@ -72,56 +73,59 @@ mda_get_range(int n, int *span, int *st, int *endp) span[i] = endp[i] - st[i] + 1; } +/* Compute products of array dimensions, ie, scale factors for subscripts */ void -mda_get_prod(int n, int *range, int *P) +mda_get_prod(int n, int *range, int *prod) { int i; - for (i = n - 2, P[n - 1] = 1; i >= 0; i--) - P[i] = P[i + 1] * range[i + 1]; + prod[n - 1] = 1; + for (i = n - 2; i >= 0; i--) + prod[i] = prod[i + 1] * range[i + 1]; } -int -tuple2linear(int n, int *tup, int *scale) +/* From products of whole-array dimensions and spans of a sub-array, + * compute offset distances needed to step through subarray within array + */ +void +mda_get_offset_values(int n, int *dist, int *prod, int *span) { int i, - lin; + j; - for (i = lin = 0; i < n; i++) - lin += tup[i] * scale[i]; - return lin; -} - -void -array2chunk_coord(int n, int *C, int *a_coord, int *c_coord) -{ - int i; - - for (i = 0; i < n; i++) - c_coord[i] = a_coord[i] / C[i]; + dist[n - 1] = 0; + for (j = n - 2; j >= 0; j--) + { + dist[j] = prod[j] - 1; + for (i = j + 1; i < n; i++) + dist[j] -= (span[i] - 1) * prod[i]; + } } /*----------------------------------------------------------------------------- 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 - -----------------------------------------------------------------------------*/ + Returns -1 if no next tuple exists, else the subscript position (0..n-1) + corresponding to the dimension to advance along. + ----------------------------------------------------------------------------- +*/ int -next_tuple(int n, int *curr, int *span) +mda_next_tuple(int n, int *curr, int *span) { int i; - if (!n) + if (n <= 0) return -1; + curr[n - 1] = (curr[n - 1] + 1) % span[n - 1]; - for (i = n - 1; i * (!curr[i]); i--) + for (i = n - 1; i && curr[i] == 0; i--) curr[i - 1] = (curr[i - 1] + 1) % span[i - 1]; if (i) return i; if (curr[0]) return 0; + return -1; } diff --git a/src/backend/utils/adt/chunk.c b/src/backend/utils/adt/chunk.c deleted file mode 100644 index 5577676949..0000000000 --- a/src/backend/utils/adt/chunk.c +++ /dev/null @@ -1,712 +0,0 @@ -/*------------------------------------------------------------------------- - * - * chunk.c - * - * 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/Attic/chunk.c,v 1.28 2000/06/18 22:44:13 tgl Exp $ - * - *------------------------------------------------------------------------- - */ -#include -#include -#include - -#include "postgres.h" - -#include "catalog/pg_type.h" -#include "fmgr.h" -#include "libpq/be-fsstubs.h" -#include "libpq/libpq-fs.h" -#include "utils/array.h" -#include "utils/memutils.h" - -#define INFTY 500000000 -#define MANY 10000 -#define MAXPAT 20 -#define quot_ceil(x,y) (((x)+(y)-1)/(y)) -#if !defined(min) -#define min(x,y) (((x) < (y))? (x) : (y)) -#endif -#if !defined(max) -#define max(x,y) (((x) > (y))? (x) : (y)) -#endif - -static CHUNK_INFO cInfo; - -/* non-export function prototypes */ -static int _FindBestChunk(int size, int *dmax, int *dbest, int dim, - int A[MAXPAT][MAXDIM + 1], int N); -static int get_next(int *d, int k, int C, int *dmax); -static void initialize_info(CHUNK_INFO *A, int ndim, int *dim, int *chunk); - -#ifdef LOARRAY -static void _ConvertToChunkFile(int n, int baseSize, int *dim, int *C, - int srcfd, int destfd); -static void read_chunk(int *chunk_no, int *C, char *a_chunk, int srcfd, - int n, int baseSize, int *PX, int *dist); -static int write_chunk(struct varlena * a_chunk, int ofile); -static int seek_and_read(int pos, int size, char *buff, int fp, int from); - -#endif -static int GetChunkSize(FILE *fd, int ndim, int dim[MAXDIM], int baseSize, - int d[MAXDIM]); - -/*------------------------------------------------------------------------ - * _ChunkArray --- - * converts an input array to chunked format using the information - * provided by the access pattern. - * Results: - * creates a new file that stores the chunked array and returns - * information about the chunked file - *----------------------------------------------------------------------- - */ -char * -_ChunkArray(int fd, - FILE *afd, - int ndim, - int *dim, - int baseSize, - int *nbytes, - char *chunkfile) -{ -#ifdef LOARRAY - int cfd = 0; - -#endif - int chunk[MAXDIM], - csize; - bool reorgFlag; - - if (chunkfile == NULL) - reorgFlag = true; - else - reorgFlag = false; - -#ifdef LOARRAY - if (reorgFlag) - /* create new LO for chunked file */ - chunkfile = _array_newLO(&cfd, fileFlag); - else - cfd = LOopen(chunkfile, O_RDONLY); - if (cfd < 0) - elog(ERROR, "Unable to open chunk file"); -#endif - - strcpy(cInfo.lo_name, chunkfile); - - /* find chunk size */ - csize = GetChunkSize(afd, ndim, dim, baseSize, chunk); - -#ifdef LOARRAY - if (reorgFlag) - /* copy data from input file to chunked file */ - _ConvertToChunkFile(ndim, baseSize, dim, chunk, fd, cfd); -#endif - - initialize_info(&cInfo, ndim, dim, chunk); - *nbytes = sizeof(CHUNK_INFO); - return (char *) &cInfo; -} - -/*-------------------------------------------------------------------------- - * GetChunkSize - * given an access pattern and array dimensionality etc, this program - * returns the dimensions of the chunk in "d" - *----------------------------------------------------------------------- - */ -static int -GetChunkSize(FILE *fd, - int ndim, - int dim[MAXDIM], - int baseSize, - int d[MAXDIM]) -{ - int N, - i, - j, - csize; - int A[MAXPAT][MAXDIM + 1], - dmax[MAXDIM]; - - /* - * ----------- read input ------------ - */ - fscanf(fd, "%d", &N); - if (N > MAXPAT) - elog(ERROR, "array_in: too many access pattern elements"); - for (i = 0; i < N; i++) - for (j = 0; j < ndim + 1; j++) - if (fscanf(fd, "%d ", &(A[i][j])) == EOF) - elog(ERROR, "array_in: bad access pattern input"); - - /* - * estimate chunk size - */ - for (i = 0; i < ndim; i++) - for (j = 0, dmax[i] = 1; j < N; j++) - if (dmax[i] < A[j][i]) - dmax[i] = A[j][i]; - csize = BLCKSZ / baseSize; - - _FindBestChunk(csize, dmax, d, ndim, A, N); - - return csize; -} - -/*------------------------------------------------------------------------- - * _FindBestChunk - * This routine does most of the number crunching to compute the - * optimal chunk shape. - * Called by GetChunkSize - *------------------------------------------------------------------------ - */ -static int -_FindBestChunk(int size, - int *dmax, - int *dbest, - int dim, - int A[MAXPAT][MAXDIM + 1], - int N) -{ - int d[MAXDIM]; - int tc, - mintc = INFTY; - - d[0] = 0; - mintc = INFTY; - while (get_next(d, dim, size, dmax)) - { - - /* - * compute the number of page fetches for a given chunk size (*d) - * and access pattern (**A) - */ - int i, - j, - nc; - - for (i = 0, tc = 0; i < N; i++) - { - for (j = 0, nc = 1; j < dim; j++) - nc *= quot_ceil(A[i][j], d[j]); - nc *= A[i][dim]; - tc += nc; - } - - /* - * tc holds the total number of page fetches - */ - if (mintc >= tc) - { - mintc = tc; - for (j = 0; j < dim; dbest[j] = d[j], j++) - ; - } - } - return mintc; -} - -/*---------------------------------------------------------------------- - * get_next - * Called by _GetBestChunk to get the next tuple in the lexicographic order - *--------------------------------------------------------------------- - */ -static int -get_next(int *d, int k, int C, int *dmax) -{ - int i, - j, - temp; - - if (!d[0]) - { - temp = C; - for (j = k - 1; j >= 0; j--) - { - d[j] = min(temp, dmax[j]); - temp = max(1, temp / d[j]); - } - return 1; - } - - for (j = 0, temp = 1; j < k; j++) - temp *= d[j]; - - for (i = k - 1; i >= 0; i--) - { - temp = temp / d[i]; - if (((temp * (d[i] + 1)) < C) && (d[i] + 1 <= dmax[i])) - break; - } - if (i < 0) - return 0; - - d[i]++; - j = C / temp; - d[i] = min(dmax[i], j / (j / d[i])); - temp = temp * d[i]; - temp = C / temp; - - for (j = k - 1; j > i; j--) - { - d[j] = min(temp, dmax[j]); - temp = max(1, temp / d[j]); - } - return 1; -} - -#ifdef LOARRAY -static char a_chunk[BLCKSZ + VARHDRSZ]; /* VARHDRSZ since a_chunk is in - * varlena format */ - -#endif - -static void -initialize_info(CHUNK_INFO *A, int ndim, int *dim, int *chunk) -{ - int i; - - for (i = 0; i < ndim; i++) - A->C[i] = chunk[i]; -} - -/*-------------------------------------------------------------------------- - * Procedure reorganize_data(): - * This procedure reads the input multidimensional array that is organised - * in the order specified by array "X" and breaks it up into chunks of - * dimensions specified in "C". - * - * This is a very slow process, since reading and writing of LARGE files - * may be involved. - * - *------------------------------------------------------------------------- - */ -#ifdef LOARRAY -static void -_ConvertToChunkFile(int n, - int baseSize, - int *dim, - int *C, - int srcfd, - int destfd) -{ - int max_chunks[MAXDIM], - chunk_no[MAXDIM]; - int PX[MAXDIM], - dist[MAXDIM]; - int csize = 1, - i, - temp; - - for (i = 0; i < n; chunk_no[i++] = 0) - { - max_chunks[i] = dim[i] / C[i]; - csize *= C[i]; - } - csize *= baseSize; - temp = csize + VARHDRSZ; - memmove(a_chunk, &temp, VARHDRSZ); - - mda_get_prod(n, dim, PX); - mda_get_offset_values(n, dist, PX, C); - for (i = 0; i < n; dist[i] *= baseSize, i++) - ; - do - { - read_chunk(chunk_no, C, &(a_chunk[VARHDRSZ]), srcfd, n, baseSize, PX, dist); - write_chunk((struct varlena *) a_chunk, destfd); - } while (next_tuple(n, chunk_no, max_chunks) != -1); -} - -/*-------------------------------------------------------------------------- - * read_chunk - * reads a chunk from the input files into a_chunk, the position of the - * chunk is specified by chunk_no - *-------------------------------------------------------------------------- - */ -static void -read_chunk(int *chunk_no, - int *C, - char *a_chunk, - int srcfd, - int n, - int baseSize, - int *PX, - int *dist) -{ - int i, - j, - cp, - unit_transfer; - int start_pos, - pos[MAXDIM]; - int indx[MAXDIM]; - int fpOff; - - for (i = start_pos = 0; i < n; i++) - { - pos[i] = chunk_no[i] * C[i]; - start_pos += pos[i] * PX[i]; - } - start_pos *= baseSize; - - /* Read a block of dimesion C starting at co-ordinates pos */ - unit_transfer = C[n - 1] * baseSize; - - for (i = 0; i < n; indx[i++] = 0) - ; - fpOff = start_pos; - seek_and_read(fpOff, unit_transfer, a_chunk, srcfd, SEEK_SET); - fpOff += unit_transfer; - cp = unit_transfer; - - while ((j = next_tuple(n - 1, indx, C)) != -1) - { - fpOff += dist[j]; - seek_and_read(fpOff, unit_transfer, &(a_chunk[cp]), srcfd, SEEK_SET); - cp += unit_transfer; - fpOff += unit_transfer; - } -} - -/*-------------------------------------------------------------------------- - * write_chunk() - * writes a chunk of size csize into the output file - *-------------------------------------------------------------------------- - */ -static int -write_chunk(struct varlena * a_chunk, int ofile) -{ - int got_n = 0; - -#ifdef LOARRAY - got_n = DatumGetInt32(DirectFunctionCall2(lowrite, - Int32GetDatum(ofile), - PointerGetDatum(a_chunk))); -#endif - return got_n; -} - -/*-------------------------------------------------------------------------- - * seek_and_read() - * seeks to the asked location in the input file and reads the - * appropriate number of blocks - * Called By: read_chunk() - *-------------------------------------------------------------------------- - */ -static int -seek_and_read(int pos, int size, char *buff, int fp, int from) -{ - struct varlena *v; - - /* Assuming only one file */ - if (DatumGetInt32(DirectFunctionCall3(lo_lseek, - Int32GetDatum(fp), - Int32GetDatum(pos), - Int32GetDatum(from))) < 0) - elog(ERROR, "File seek error"); -#ifdef LOARRAY - v = (struct varlena *) - DatumGetPointer(DirectFunctionCall2(loread, - Int32GetDatum(fp), - Int32GetDatum(size))); -#endif - if (VARSIZE(v) - VARHDRSZ < size) - elog(ERROR, "File read error"); - memmove(buff, VARDATA(v), size); - pfree(v); - return 1; - -} - -#endif /* LOARRAY */ - -/*---------------------------------------------------------------------------- - * _ReadChunkArray - * returns the subarray specified bu the range indices "st" and "endp" - * from the chunked array stored in file "fp" - *--------------------------------------------------------------------------- - */ -int -_ReadChunkArray(int *st, - int *endp, - int bsize, - int fp, - char *destfp, - ArrayType *array, - int isDestLO, - bool *isNull) -{ - int i, - j, - jj; - int n, - temp, - words_read; - int chunk_span[MAXDIM], - chunk_off[MAXDIM]; - int chunk_st[MAXDIM], - chunk_end[MAXDIM]; - int block_seek; - - int bptr, - *C, - csize, - *dim, - *lb; - int range_st[MAXDIM], - range_end[MAXDIM], - range[MAXDIM], - array_span[MAXDIM]; - int PA[MAXDIM], - PCHUNK[MAXDIM], - PC[MAXDIM]; - int to_read; - int cdist[MAXDIM], - adist[MAXDIM]; - int dist[MAXDIM], - temp_seek; - - int srcOff; /* Needed since LO don't understand - * SEEK_CUR */ - char *baseDestFp = (char *) destfp; - - CHUNK_INFO *A = (CHUNK_INFO *) ARR_DATA_PTR(array); - - n = ARR_NDIM(array); - dim = ARR_DIMS(array); - lb = ARR_LBOUND(array); - C = A->C; - - csize = C[n - 1]; - PC[n - 1] = 1; - temp = dim[n - 1] / C[n - 1]; - for (i = n - 2; i >= 0; i--) - { - PC[i] = PC[i + 1] * temp; - temp = dim[i] / C[i]; - csize *= C[i]; - } - - for (i = 0; i < n; st[i] -= lb[i], endp[i] -= lb[i], i++) - ; - mda_get_prod(n, C, PCHUNK); - mda_get_range(n, array_span, st, endp); - mda_get_prod(n, array_span, PA); - - array2chunk_coord(n, C, st, chunk_st); - array2chunk_coord(n, C, endp, chunk_end); - mda_get_range(n, chunk_span, chunk_st, chunk_end); - mda_get_offset_values(n, dist, PC, chunk_span); - - for (i = 0; i < n; i++) - { - range_st[i] = st[i]; - range_end[i] = min(chunk_st[i] * C[i] + C[i] - 1, endp[i]); - } - - for (i = j = 0; i < n; i++) - j += chunk_st[i] * PC[i]; - temp_seek = srcOff = j * csize * bsize; - if (DatumGetInt32(DirectFunctionCall3(lo_lseek, - Int32GetDatum(fp), - Int32GetDatum(srcOff), - Int32GetDatum(SEEK_SET))) < 0) - RETURN_NULL(int); - - jj = n - 1; - for (i = 0; i < n; chunk_off[i++] = 0) - ; - words_read = 0; - temp_seek = 0; - do - { - /* Write chunk (chunk_st) to output buffer */ - mda_get_range(n, array_span, range_st, range_end); - mda_get_offset_values(n, adist, PA, array_span); - mda_get_offset_values(n, cdist, PCHUNK, array_span); - for (i = 0; i < n; range[i] = range_st[i] - st[i], i++); - bptr = tuple2linear(n, range, PA); - for (i = 0; i < n; range[i++] = 0); - j = n - 1; - bptr *= bsize; - if (isDestLO) - { - if (DatumGetInt32(DirectFunctionCall3(lo_lseek, - Int32GetDatum((int32) destfp), - Int32GetDatum(bptr), - Int32GetDatum(SEEK_SET))) < 0) - RETURN_NULL(int); - } - else - destfp = baseDestFp + bptr; - for (i = 0, block_seek = 0; i < n; i++) - block_seek += (range_st[i] - (chunk_st[i] + chunk_off[i]) - * C[i]) * PCHUNK[i]; - if (dist[jj] + block_seek + temp_seek) - { - temp = (dist[jj] * csize + block_seek + temp_seek) * bsize; - srcOff += temp; - if (DatumGetInt32(DirectFunctionCall3(lo_lseek, - Int32GetDatum(fp), - Int32GetDatum(srcOff), - Int32GetDatum(SEEK_SET))) < 0) - RETURN_NULL(int); - } - for (i = n - 1, to_read = bsize; i >= 0; - to_read *= min(C[i], array_span[i]), i--) - if (cdist[i] || adist[i]) - break; - do - { - if (cdist[j]) - { - srcOff += (cdist[j] * bsize); - if (DatumGetInt32(DirectFunctionCall3(lo_lseek, - Int32GetDatum(fp), - Int32GetDatum(srcOff), - Int32GetDatum(SEEK_SET))) < 0) - RETURN_NULL(int); - } - block_seek += cdist[j]; - bptr += adist[j] * bsize; - if (isDestLO) - { - if (DatumGetInt32(DirectFunctionCall3(lo_lseek, - Int32GetDatum((int32) destfp), - Int32GetDatum(bptr), - Int32GetDatum(SEEK_SET))) < 0) - RETURN_NULL(int); - } - else - destfp = baseDestFp + bptr; - temp = _LOtransfer((char **) &destfp, to_read, 1, (char **) &fp, 1, isDestLO); - if (temp < to_read) - RETURN_NULL(int); - srcOff += to_read; - words_read += to_read; - bptr += to_read; - block_seek += (to_read / bsize); - - /* - * compute next tuple in *range - */ - { - int x; - - if (!(i + 1)) - j = -1; - else - { - range[i] = (range[i] + 1) % array_span[i]; - for (x = i; x * (!range[x]); x--) - range[x - 1] = (range[x - 1] + 1) % array_span[x - 1]; - if (x) - j = x; - else - { - if (range[0]) - j = 0; - else - j = -1; - } - } - } - - /* - * end of compute next tuple -- j is set to -1 if tuple - * generation is over - */ - } while (j != -1); - - block_seek = csize - block_seek; - temp_seek = block_seek; - jj = next_tuple(n, chunk_off, chunk_span); - if (jj == -1) - break; - range_st[jj] = (chunk_st[jj] + chunk_off[jj]) * C[jj]; - range_end[jj] = min(range_st[jj] + C[jj] - 1, endp[jj]); - - for (i = jj + 1; i < n; i++) - { - range_st[i] = st[i]; - range_end[i] = min((chunk_st[i] + chunk_off[i]) * C[i] + C[i] - 1, endp[i]); - } - } while (jj != -1); - return words_read; -} - -/*------------------------------------------------------------------------ - * _ReadChunkArray1El - * returns one element of the chunked array as specified by the index "st" - * the chunked file descriptor is "fp" - *------------------------------------------------------------------------- - */ -struct varlena * -_ReadChunkArray1El(int *st, - int bsize, - int fp, - ArrayType *array, - bool *isNull) -{ - int i, - j, - n, - temp, - srcOff; - int chunk_st[MAXDIM]; - - int *C, - csize, - *dim, - *lb; - int PCHUNK[MAXDIM], - PC[MAXDIM]; - - CHUNK_INFO *A = (CHUNK_INFO *) ARR_DATA_PTR(array); - - n = ARR_NDIM(array); - lb = ARR_LBOUND(array); - C = A->C; - dim = ARR_DIMS(array); - - csize = C[n - 1]; - PC[n - 1] = 1; - temp = dim[n - 1] / C[n - 1]; - for (i = n - 2; i >= 0; i--) - { - PC[i] = PC[i + 1] * temp; - temp = dim[i] / C[i]; - csize *= C[i]; - } - - for (i = 0; i < n; st[i] -= lb[i], i++); - mda_get_prod(n, C, PCHUNK); - - array2chunk_coord(n, C, st, chunk_st); - - for (i = j = 0; i < n; i++) - j += chunk_st[i] * PC[i]; - srcOff = j * csize; - - for (i = 0; i < n; i++) - srcOff += (st[i] - chunk_st[i] * C[i]) * PCHUNK[i]; - - srcOff *= bsize; - if (DatumGetInt32(DirectFunctionCall3(lo_lseek, - Int32GetDatum(fp), - Int32GetDatum(srcOff), - Int32GetDatum(SEEK_SET))) < 0) - RETURN_NULL(struct varlena *); -#ifdef LOARRAY - return (struct varlena *) - DatumGetPointer(DirectFunctionCall2(loread, - Int32GetDatum(fp), - Int32GetDatum(bsize))); -#endif - return (struct varlena *) 0; -} diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h index c77c3c4094..d14f9287e2 100644 --- a/src/include/catalog/pg_type.h +++ b/src/include/catalog/pg_type.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_type.h,v 1.92 2000/07/07 19:24:41 petere Exp $ + * $Id: pg_type.h,v 1.93 2000/07/22 03:34:28 tgl Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -76,11 +76,11 @@ CATALOG(pg_type) BOOTSTRAP * If typelem is not 0 then it identifies another row in pg_type. * The current type can then be subscripted like an array yielding * values of type typelem. A non-zero typelem does not guarantee - * this type to be an array type; ordinary fixed-length types can - * also be subscripted (e.g., oidvector). Variable-length types - * can *not* be turned into pseudo-arrays like that. Hence, the - * way to determine whether a type is an array type is typelem != - * 0 and typlen < 0. + * this type to be a "real" array type; some ordinary fixed-length + * types can also be subscripted (e.g., oidvector). Variable-length + * types can *not* be turned into pseudo-arrays like that. Hence, + * the way to determine whether a type is a "true" array type is + * typelem != 0 and typlen < 0. */ Oid typelem; regproc typinput; @@ -282,7 +282,7 @@ DESCR("filename used in system tables"); DATA(insert OID = 628 ( line PGUID 32 48 f b t \054 0 701 line_in line_out line_in line_out d p _null_ )); DESCR("geometric line '(pt1,pt2)'"); #define LINEOID 628 -DATA(insert OID = 629 ( _line PGUID -1 -1 f b t \054 0 628 array_in array_out array_in array_out d p _null_ )); +DATA(insert OID = 629 ( _line PGUID -1 -1 f b t \054 0 628 array_in array_out array_in array_out d x _null_ )); DESCR(""); /* OIDS 700 - 799 */ @@ -309,11 +309,11 @@ DESCR(""); DATA(insert OID = 718 ( circle PGUID 24 47 f b t \054 0 0 circle_in circle_out circle_in circle_out d p _null_ )); DESCR("geometric circle '(center,radius)'"); #define CIRCLEOID 718 -DATA(insert OID = 719 ( _circle PGUID -1 -1 f b t \054 0 718 array_in array_out array_in array_out d p _null_ )); +DATA(insert OID = 719 ( _circle PGUID -1 -1 f b t \054 0 718 array_in array_out array_in array_out d x _null_ )); DATA(insert OID = 790 ( money PGUID 4 24 f b t \054 0 0 cash_in cash_out cash_in cash_out i p _null_ )); DESCR("$d,ddd.cc, money"); #define CASHOID 790 -DATA(insert OID = 791 ( _money PGUID -1 -1 f b t \054 0 790 array_in array_out array_in array_out i p _null_ )); +DATA(insert OID = 791 ( _money PGUID -1 -1 f b t \054 0 790 array_in array_out array_in array_out i x _null_ )); /* OIDS 800 - 899 */ DATA(insert OID = 829 ( macaddr PGUID 6 -1 f b t \054 0 0 macaddr_in macaddr_out macaddr_in macaddr_out i p _null_ )); @@ -328,34 +328,34 @@ DESCR("network IP address/netmask, network address"); /* OIDS 900 - 999 */ /* OIDS 1000 - 1099 */ -DATA(insert OID = 1000 ( _bool PGUID -1 -1 f b t \054 0 16 array_in array_out array_in array_out i p _null_ )); -DATA(insert OID = 1001 ( _bytea PGUID -1 -1 f b t \054 0 17 array_in array_out array_in array_out i p _null_ )); -DATA(insert OID = 1002 ( _char PGUID -1 -1 f b t \054 0 18 array_in array_out array_in array_out i p _null_ )); -DATA(insert OID = 1003 ( _name PGUID -1 -1 f b t \054 0 19 array_in array_out array_in array_out i p _null_ )); -DATA(insert OID = 1005 ( _int2 PGUID -1 -1 f b t \054 0 21 array_in array_out array_in array_out i p _null_ )); -DATA(insert OID = 1006 ( _int2vector PGUID -1 -1 f b t \054 0 22 array_in array_out array_in array_out i p _null_ )); -DATA(insert OID = 1007 ( _int4 PGUID -1 -1 f b t \054 0 23 array_in array_out array_in array_out i p _null_ )); -DATA(insert OID = 1008 ( _regproc PGUID -1 -1 f b t \054 0 24 array_in array_out array_in array_out i p _null_ )); -DATA(insert OID = 1009 ( _text PGUID -1 -1 f b t \054 0 25 array_in array_out array_in array_out i p _null_ )); -DATA(insert OID = 1028 ( _oid PGUID -1 -1 f b t \054 0 26 array_in array_out array_in array_out i p _null_ )); -DATA(insert OID = 1010 ( _tid PGUID -1 -1 f b t \054 0 27 array_in array_out array_in array_out i p _null_ )); -DATA(insert OID = 1011 ( _xid PGUID -1 -1 f b t \054 0 28 array_in array_out array_in array_out i p _null_ )); -DATA(insert OID = 1012 ( _cid PGUID -1 -1 f b t \054 0 29 array_in array_out array_in array_out i p _null_ )); -DATA(insert OID = 1013 ( _oidvector PGUID -1 -1 f b t \054 0 30 array_in array_out array_in array_out i p _null_ )); -DATA(insert OID = 1014 ( _bpchar PGUID -1 -1 f b t \054 0 1042 array_in array_out array_in array_out i p _null_ )); -DATA(insert OID = 1015 ( _varchar PGUID -1 -1 f b t \054 0 1043 array_in array_out array_in array_out i p _null_ )); -DATA(insert OID = 1016 ( _int8 PGUID -1 -1 f b t \054 0 20 array_in array_out array_in array_out d p _null_ )); -DATA(insert OID = 1017 ( _point PGUID -1 -1 f b t \054 0 600 array_in array_out array_in array_out d p _null_ )); -DATA(insert OID = 1018 ( _lseg PGUID -1 -1 f b t \054 0 601 array_in array_out array_in array_out d p _null_ )); -DATA(insert OID = 1019 ( _path PGUID -1 -1 f b t \054 0 602 array_in array_out array_in array_out d p _null_ )); -DATA(insert OID = 1020 ( _box PGUID -1 -1 f b t \073 0 603 array_in array_out array_in array_out d p _null_ )); -DATA(insert OID = 1021 ( _float4 PGUID -1 -1 f b t \054 0 700 array_in array_out array_in array_out i p _null_ )); -DATA(insert OID = 1022 ( _float8 PGUID -1 -1 f b t \054 0 701 array_in array_out array_in array_out d p _null_ )); -DATA(insert OID = 1023 ( _abstime PGUID -1 -1 f b t \054 0 702 array_in array_out array_in array_out i p _null_ )); -DATA(insert OID = 1024 ( _reltime PGUID -1 -1 f b t \054 0 703 array_in array_out array_in array_out i p _null_ )); -DATA(insert OID = 1025 ( _tinterval PGUID -1 -1 f b t \054 0 704 array_in array_out array_in array_out i p _null_ )); -DATA(insert OID = 1026 ( _filename PGUID -1 -1 f b t \054 0 605 array_in array_out array_in array_out i p _null_ )); -DATA(insert OID = 1027 ( _polygon PGUID -1 -1 f b t \054 0 604 array_in array_out array_in array_out d p _null_ )); +DATA(insert OID = 1000 ( _bool PGUID -1 -1 f b t \054 0 16 array_in array_out array_in array_out i x _null_ )); +DATA(insert OID = 1001 ( _bytea PGUID -1 -1 f b t \054 0 17 array_in array_out array_in array_out i x _null_ )); +DATA(insert OID = 1002 ( _char PGUID -1 -1 f b t \054 0 18 array_in array_out array_in array_out i x _null_ )); +DATA(insert OID = 1003 ( _name PGUID -1 -1 f b t \054 0 19 array_in array_out array_in array_out i x _null_ )); +DATA(insert OID = 1005 ( _int2 PGUID -1 -1 f b t \054 0 21 array_in array_out array_in array_out i x _null_ )); +DATA(insert OID = 1006 ( _int2vector PGUID -1 -1 f b t \054 0 22 array_in array_out array_in array_out i x _null_ )); +DATA(insert OID = 1007 ( _int4 PGUID -1 -1 f b t \054 0 23 array_in array_out array_in array_out i x _null_ )); +DATA(insert OID = 1008 ( _regproc PGUID -1 -1 f b t \054 0 24 array_in array_out array_in array_out i x _null_ )); +DATA(insert OID = 1009 ( _text PGUID -1 -1 f b t \054 0 25 array_in array_out array_in array_out i x _null_ )); +DATA(insert OID = 1028 ( _oid PGUID -1 -1 f b t \054 0 26 array_in array_out array_in array_out i x _null_ )); +DATA(insert OID = 1010 ( _tid PGUID -1 -1 f b t \054 0 27 array_in array_out array_in array_out i x _null_ )); +DATA(insert OID = 1011 ( _xid PGUID -1 -1 f b t \054 0 28 array_in array_out array_in array_out i x _null_ )); +DATA(insert OID = 1012 ( _cid PGUID -1 -1 f b t \054 0 29 array_in array_out array_in array_out i x _null_ )); +DATA(insert OID = 1013 ( _oidvector PGUID -1 -1 f b t \054 0 30 array_in array_out array_in array_out i x _null_ )); +DATA(insert OID = 1014 ( _bpchar PGUID -1 -1 f b t \054 0 1042 array_in array_out array_in array_out i x _null_ )); +DATA(insert OID = 1015 ( _varchar PGUID -1 -1 f b t \054 0 1043 array_in array_out array_in array_out i x _null_ )); +DATA(insert OID = 1016 ( _int8 PGUID -1 -1 f b t \054 0 20 array_in array_out array_in array_out d x _null_ )); +DATA(insert OID = 1017 ( _point PGUID -1 -1 f b t \054 0 600 array_in array_out array_in array_out d x _null_ )); +DATA(insert OID = 1018 ( _lseg PGUID -1 -1 f b t \054 0 601 array_in array_out array_in array_out d x _null_ )); +DATA(insert OID = 1019 ( _path PGUID -1 -1 f b t \054 0 602 array_in array_out array_in array_out d x _null_ )); +DATA(insert OID = 1020 ( _box PGUID -1 -1 f b t \073 0 603 array_in array_out array_in array_out d x _null_ )); +DATA(insert OID = 1021 ( _float4 PGUID -1 -1 f b t \054 0 700 array_in array_out array_in array_out i x _null_ )); +DATA(insert OID = 1022 ( _float8 PGUID -1 -1 f b t \054 0 701 array_in array_out array_in array_out d x _null_ )); +DATA(insert OID = 1023 ( _abstime PGUID -1 -1 f b t \054 0 702 array_in array_out array_in array_out i x _null_ )); +DATA(insert OID = 1024 ( _reltime PGUID -1 -1 f b t \054 0 703 array_in array_out array_in array_out i x _null_ )); +DATA(insert OID = 1025 ( _tinterval PGUID -1 -1 f b t \054 0 704 array_in array_out array_in array_out i x _null_ )); +DATA(insert OID = 1026 ( _filename PGUID -1 -1 f b t \054 0 605 array_in array_out array_in array_out i x _null_ )); +DATA(insert OID = 1027 ( _polygon PGUID -1 -1 f b t \054 0 604 array_in array_out array_in array_out d x _null_ )); /* * Note: the size of aclitem needs to match sizeof(AclItem) in acl.h. * Thanks to some padding, this will be 8 on all platforms. @@ -364,10 +364,10 @@ DATA(insert OID = 1027 ( _polygon PGUID -1 -1 f b t \054 0 604 array_in array #define ACLITEMSIZE 8 DATA(insert OID = 1033 ( aclitem PGUID 8 -1 f b t \054 0 0 aclitemin aclitemout aclitemin aclitemout i p _null_ )); DESCR("access control list"); -DATA(insert OID = 1034 ( _aclitem PGUID -1 -1 f b t \054 0 1033 array_in array_out array_in array_out i p _null_ )); -DATA(insert OID = 1040 ( _macaddr PGUID -1 -1 f b t \054 0 829 array_in array_out array_in array_out i p _null_ )); -DATA(insert OID = 1041 ( _inet PGUID -1 -1 f b t \054 0 869 array_in array_out array_in array_out i p _null_ )); -DATA(insert OID = 651 ( _cidr PGUID -1 -1 f b t \054 0 650 array_in array_out array_in array_out i p _null_ )); +DATA(insert OID = 1034 ( _aclitem PGUID -1 -1 f b t \054 0 1033 array_in array_out array_in array_out i x _null_ )); +DATA(insert OID = 1040 ( _macaddr PGUID -1 -1 f b t \054 0 829 array_in array_out array_in array_out i x _null_ )); +DATA(insert OID = 1041 ( _inet PGUID -1 -1 f b t \054 0 869 array_in array_out array_in array_out i x _null_ )); +DATA(insert OID = 651 ( _cidr PGUID -1 -1 f b t \054 0 650 array_in array_out array_in array_out i x _null_ )); DATA(insert OID = 1042 ( bpchar PGUID -1 -1 f b t \054 0 0 bpcharin bpcharout bpcharin bpcharout i p _null_ )); DESCR("char(length), blank-padded string, fixed storage length"); #define BPCHAROID 1042 @@ -383,33 +383,33 @@ DESCR("hh:mm:ss, ANSI SQL time"); #define TIMEOID 1083 /* OIDS 1100 - 1199 */ -DATA(insert OID = 1182 ( _date PGUID -1 -1 f b t \054 0 1082 array_in array_out array_in array_out i p _null_ )); -DATA(insert OID = 1183 ( _time PGUID -1 -1 f b t \054 0 1083 array_in array_out array_in array_out d p _null_ )); +DATA(insert OID = 1182 ( _date PGUID -1 -1 f b t \054 0 1082 array_in array_out array_in array_out i x _null_ )); +DATA(insert OID = 1183 ( _time PGUID -1 -1 f b t \054 0 1083 array_in array_out array_in array_out d x _null_ )); DATA(insert OID = 1184 ( timestamp PGUID 8 47 f b t \054 0 0 timestamp_in timestamp_out timestamp_in timestamp_out d p _null_ )); DESCR("date and time"); #define TIMESTAMPOID 1184 -DATA(insert OID = 1185 ( _timestamp PGUID -1 -1 f b t \054 0 1184 array_in array_out array_in array_out d p _null_ )); +DATA(insert OID = 1185 ( _timestamp PGUID -1 -1 f b t \054 0 1184 array_in array_out array_in array_out d x _null_ )); DATA(insert OID = 1186 ( interval PGUID 12 47 f b t \054 0 0 interval_in interval_out interval_in interval_out d p _null_ )); DESCR("@ , time interval"); #define INTERVALOID 1186 -DATA(insert OID = 1187 ( _interval PGUID -1 -1 f b t \054 0 1186 array_in array_out array_in array_out d p _null_ )); +DATA(insert OID = 1187 ( _interval PGUID -1 -1 f b t \054 0 1186 array_in array_out array_in array_out d x _null_ )); /* OIDS 1200 - 1299 */ -DATA(insert OID = 1231 ( _numeric PGUID -1 -1 f b t \054 0 1700 array_in array_out array_in array_out i p _null_ )); +DATA(insert OID = 1231 ( _numeric PGUID -1 -1 f b t \054 0 1700 array_in array_out array_in array_out i x _null_ )); DATA(insert OID = 1266 ( timetz PGUID 12 22 f b t \054 0 0 timetz_in timetz_out timetz_in timetz_out d p _null_ )); DESCR("hh:mm:ss, ANSI SQL time"); #define TIMETZOID 1266 -DATA(insert OID = 1270 ( _timetz PGUID -1 -1 f b t \054 0 1266 array_in array_out array_in array_out d p _null_ )); +DATA(insert OID = 1270 ( _timetz PGUID -1 -1 f b t \054 0 1266 array_in array_out array_in array_out d x _null_ )); /* OIDS 1500 - 1599 */ DATA(insert OID = 1560 ( bit PGUID -1 -1 f b t \054 0 0 zpbit_in zpbit_out zpbit_in zpbit_out i p _null_ )); DESCR("fixed-length bit string"); #define ZPBITOID 1560 -DATA(insert OID = 1561 ( _bit PGUID -1 -1 f b t \054 0 1560 array_in array_out array_in array_out i p _null_ )); +DATA(insert OID = 1561 ( _bit PGUID -1 -1 f b t \054 0 1560 array_in array_out array_in array_out i x _null_ )); DATA(insert OID = 1562 ( varbit PGUID -1 -1 f b t \054 0 0 varbit_in varbit_out varbit_in varbit_out i p _null_ )); DESCR("fixed-length bit string"); #define VARBITOID 1562 -DATA(insert OID = 1563 ( _varbit PGUID -1 -1 f b t \054 0 1562 array_in array_out array_in array_out i p _null_ )); +DATA(insert OID = 1563 ( _varbit PGUID -1 -1 f b t \054 0 1562 array_in array_out array_in array_out i x _null_ )); /* OIDS 1600 - 1699 */ DATA(insert OID = 1625 ( lztext PGUID -1 -1 f b t \054 0 0 lztextin lztextout lztextin lztextout i x _null_ )); diff --git a/src/include/utils/array.h b/src/include/utils/array.h index 4d915e0665..590e79f06d 100644 --- a/src/include/utils/array.h +++ b/src/include/utils/array.h @@ -5,18 +5,18 @@ * following files: * utils/adt/arrayfuncs.c * utils/adt/arrayutils.c - * utils/adt/chunk.c * * * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: array.h,v 1.26 2000/07/17 03:05:32 tgl Exp $ + * $Id: array.h,v 1.27 2000/07/22 03:34:35 tgl Exp $ * * NOTES - * XXX the data array should be MAXALIGN'd -- notice that the array - * allocation code does not allocate the extra space required for this, - * even though the array-packing code does the MAXALIGNs. + * XXX the data array should be MAXALIGN'd -- currently we only INTALIGN + * which is NOT good enough for, eg, arrays of Interval. Changing this + * will break existing user tables so hold off until we have some other + * reason to break user tables (like WAL). * *------------------------------------------------------------------------- */ @@ -34,6 +34,7 @@ typedef struct int32 size; /* total array size (varlena requirement) */ int ndim; /* # of dimensions */ int flags; /* implementation flags */ + /* flags field is currently unused, always zero. */ } ArrayType; /* @@ -46,35 +47,8 @@ typedef struct #define PG_RETURN_ARRAYTYPE_P(x) PG_RETURN_POINTER(x) /* - * bitmask of ArrayType flags field: - * 1st bit - large object flag - * 2nd bit - chunk flag (array is chunked if set) - * 3rd,4th,&5th bit - large object type (used only if bit 1 is set) - */ -#define ARR_LOB_FLAG (0x1) -#define ARR_CHK_FLAG (0x2) -#define ARR_OBJ_MASK (0x1c) - -#define ARR_SIZE(a) (((ArrayType *) a)->size) -#define ARR_NDIM(a) (((ArrayType *) a)->ndim) -#define ARR_FLAGS(a) (((ArrayType *) a)->flags) - -#define ARR_IS_LO(a) \ - (((ArrayType *) a)->flags & ARR_LOB_FLAG) -#define SET_LO_FLAG(f,a) \ - (((ArrayType *) a)->flags |= ((f) ? ARR_LOB_FLAG : 0x0)) - -#define ARR_IS_CHUNKED(a) \ - (((ArrayType *) a)->flags & ARR_CHK_FLAG) -#define SET_CHUNK_FLAG(f,a) \ - (((ArrayType *) a)->flags |= ((f) ? ARR_CHK_FLAG : 0x0)) - -#define ARR_OBJ_TYPE(a) \ - ((ARR_FLAGS(a) & ARR_OBJ_MASK) >> 2) -#define SET_OBJ_TYPE(f,a) \ - ((ARR_FLAGS(a)&= ~ARR_OBJ_MASK), (ARR_FLAGS(a)|=((f<<2)&ARR_OBJ_MASK))) - -/* + * Access macros for array header fields. + * * ARR_DIMS returns a pointer to an array of array dimensions (number of * elements along the various array axes). * @@ -85,39 +59,27 @@ typedef struct * * Unlike C, the default lower bound is 1. */ -#define ARR_DIMS(a) \ - ((int *) (((char *) a) + sizeof(ArrayType))) -#define ARR_LBOUND(a) \ - ((int *) (((char *) a) + sizeof(ArrayType) + \ - (sizeof(int) * (((ArrayType *) a)->ndim)))) +#define ARR_SIZE(a) (((ArrayType *) (a))->size) +#define ARR_NDIM(a) (((ArrayType *) (a))->ndim) -/* - * Returns a pointer to the actual array data. - */ -#define ARR_DATA_PTR(a) \ - (((char *) a) + \ - MAXALIGN(sizeof(ArrayType) + 2 * (sizeof(int) * (a)->ndim))) +#define ARR_DIMS(a) \ + ((int *) (((char *) (a)) + sizeof(ArrayType))) +#define ARR_LBOUND(a) \ + ((int *) (((char *) (a)) + sizeof(ArrayType) + \ + (sizeof(int) * ARR_NDIM(a)))) /* * The total array header size for an array of dimension n (in bytes). */ #define ARR_OVERHEAD(n) \ - (MAXALIGN(sizeof(ArrayType) + 2 * (n) * sizeof(int))) + (MAXALIGN(sizeof(ArrayType) + 2 * sizeof(int) * (n))) -/*------------------------------------------------------------------------ - * Miscellaneous helper definitions and routines for arrayfuncs.c - *------------------------------------------------------------------------ +/* + * Returns a pointer to the actual array data. */ +#define ARR_DATA_PTR(a) \ + (((char *) (a)) + ARR_OVERHEAD(ARR_NDIM(a))) -#define RETURN_NULL(type) do { *isNull = true; return (type) 0; } while (0) - -#define NAME_LEN 30 - -typedef struct -{ - char lo_name[NAME_LEN]; - int C[MAXDIM]; -} CHUNK_INFO; /* * prototypes for functions defined in arrayfuncs.c @@ -134,13 +96,16 @@ extern ArrayType *array_set(ArrayType *array, int nSubscripts, int *indx, Datum dataValue, bool elmbyval, int elmlen, int arraylen, bool *isNull); -extern ArrayType *array_clip(ArrayType *array, int nSubscripts, - int *upperIndx, int *lowerIndx, - bool elmbyval, int elmlen, bool *isNull); -extern ArrayType *array_assgn(ArrayType *array, int nSubscripts, - int *upperIndx, int *lowerIndx, - ArrayType *newArr, - bool elmbyval, int elmlen, bool *isNull); +extern ArrayType *array_get_slice(ArrayType *array, int nSubscripts, + int *upperIndx, int *lowerIndx, + bool elmbyval, int elmlen, + int arraylen, bool *isNull); +extern ArrayType *array_set_slice(ArrayType *array, int nSubscripts, + int *upperIndx, int *lowerIndx, + ArrayType *srcArray, + bool elmbyval, int elmlen, + int arraylen, bool *isNull); + extern Datum array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType); extern ArrayType *construct_array(Datum *elems, int nelems, @@ -149,35 +114,18 @@ extern void deconstruct_array(ArrayType *array, bool elmbyval, int elmlen, char elmalign, Datum **elemsp, int *nelemsp); -extern int _LOtransfer(char **destfd, int size, int nitems, char **srcfd, - int isSrcLO, int isDestLO); -extern char *_array_newLO(int *fd, int flag); - /* * prototypes for functions defined in arrayutils.c - * [these names seem to be too generic. Add prefix for arrays? -- AY] */ -extern int GetOffset(int n, int *dim, int *lb, int *indx); -extern int getNitems(int n, int *a); -extern int compute_size(int *st, int *endp, int n, int base); -extern void mda_get_offset_values(int n, int *dist, int *PC, int *span); +extern int ArrayGetOffset(int n, int *dim, int *lb, int *indx); +extern int ArrayGetOffset0(int n, int *tup, int *scale); +extern int ArrayGetNItems(int n, int *a); extern void mda_get_range(int n, int *span, int *st, int *endp); -extern void mda_get_prod(int n, int *range, int *P); -extern int tuple2linear(int n, int *tup, int *scale); -extern void array2chunk_coord(int n, int *C, int *a_coord, int *c_coord); -extern int next_tuple(int n, int *curr, int *span); - -/* - * prototypes for functions defined in chunk.c - */ -extern char *_ChunkArray(int fd, FILE *afd, int ndim, int *dim, int baseSize, - int *nbytes, char *chunkfile); -extern int _ReadChunkArray(int *st, int *endp, int bsize, int fp, - char *destfp, ArrayType *array, int isDestLO, bool *isNull); -extern struct varlena *_ReadChunkArray1El(int *st, int bsize, int fp, - ArrayType *array, bool *isNull); +extern void mda_get_prod(int n, int *range, int *prod); +extern void mda_get_offset_values(int n, int *dist, int *prod, int *span); +extern int mda_next_tuple(int n, int *curr, int *span); #endif /* ARRAY_H */