X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=src%2Fbackend%2Futils%2Fadt%2Farrayfuncs.c;h=aae18aa047fc464691589be7b2911d844a43f847;hb=ff7b9f55410bbfbd017af331d23371ab61b63d5e;hp=f8fe7e42229878276d4c7b4f0bdd4d871a15175c;hpb=210055ad614ae845686fdf9f8fc6b60301689cc8;p=postgresql diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c index f8fe7e4222..aae18aa047 100644 --- a/src/backend/utils/adt/arrayfuncs.c +++ b/src/backend/utils/adt/arrayfuncs.c @@ -3,34 +3,29 @@ * arrayfuncs.c * Special functions for arrays. * - * Copyright (c) 1994, Regents of the University of California + * 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.39 1999/05/03 19:09:59 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.58 2000/06/14 05:24:48 tgl Exp $ * *------------------------------------------------------------------------- */ #include -#include -#include -#include #include "postgres.h" #include "catalog/catalog.h" #include "catalog/pg_type.h" - -#include "utils/syscache.h" -#include "utils/memutils.h" -#include "storage/fd.h" #include "fmgr.h" -#include "utils/array.h" -#include "utils/elog.h" - -#include "libpq/libpq-fs.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 "=" @@ -73,7 +68,7 @@ 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 int ArrayCastAndSet(char *src, bool typbyval, int typlen, char *dest); +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 int array_read(char *destptr, int eltsize, int nitems, char *srcptr); static char *array_seek(char *ptr, int eltsize, int nitems); @@ -81,16 +76,17 @@ static char *array_seek(char *ptr, int eltsize, int nitems); /*--------------------------------------------------------------------- * array_in : * converts an array from the external format in "string" to - * it internal format. + * its internal format. * return value : * the internal representation of the input array *-------------------------------------------------------------------- */ -char * -array_in(char *string, /* input array in external form */ - Oid element_type, /* type OID of an array element */ - int32 typmod) +Datum +array_in(PG_FUNCTION_ARGS) { + char *string = PG_GETARG_CSTRING(0); /* external form */ + Oid element_type = PG_GETARG_OID(1); /* type of an array element */ + int32 typmod = PG_GETARG_INT32(2); /* typmod for array elements */ int typlen; bool typbyval, done; @@ -106,7 +102,7 @@ array_in(char *string, /* input array in external form */ nitems; int32 nbytes; char *dataPtr; - ArrayType *retval = NULL; + ArrayType *retval; int ndim, dim[MAXDIM], lBound[MAXDIM]; @@ -188,11 +184,10 @@ array_in(char *string, /* input array in external form */ nitems = getNitems(ndim, dim); if (nitems == 0) { - char *emptyArray = palloc(sizeof(ArrayType)); - - MemSet(emptyArray, 0, sizeof(ArrayType)); - *(int32 *) emptyArray = sizeof(ArrayType); - return emptyArray; + retval = (ArrayType *) palloc(sizeof(ArrayType)); + MemSet(retval, 0, sizeof(ArrayType)); + *(int32 *) retval = sizeof(ArrayType); + PG_RETURN_POINTER(retval); } if (*p == '{') @@ -200,7 +195,7 @@ array_in(char *string, /* input array in external form */ /* array not a large object */ dataPtr = (char *) _ReadArrayStr(p, nitems, ndim, dim, &inputproc, typelem, typmod, typdelim, typlen, typbyval, typalign, - &nbytes); + &nbytes); nbytes += ARR_OVERHEAD(ndim); retval = (ArrayType *) palloc(nbytes); MemSet(retval, 0, nbytes); @@ -240,13 +235,14 @@ array_in(char *string, /* input array in external form */ memmove(ARR_DATA_PTR(retval), dataPtr, bytes); #endif elog(ERROR, "large object arrays not supported"); + PG_RETURN_NULL(); } pfree(string_save); - return (char *) retval; + PG_RETURN_POINTER(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 *----------------------------------------------------------------------------- @@ -446,7 +442,10 @@ _ReadArrayStr(char *arrayStr, *q = '\0'; if (i >= nitems) elog(ERROR, "array_in: illformed array constant"); - values[i] = (*fmgr_faddr(inputproc)) (p, typelem, typmod); + values[i] = (char *) FunctionCall3(inputproc, + CStringGetDatum(p), + ObjectIdGetDatum(typelem), + Int32GetDatum(typmod)); p = ++q; if (!eoArray) @@ -477,7 +476,7 @@ _ReadArrayStr(char *arrayStr, if (values[i]) { if (typalign == 'd') - *nbytes += DOUBLEALIGN(*(int32 *) values[i]); + *nbytes += MAXALIGN(*(int32 *) values[i]); else *nbytes += INTALIGN(*(int32 *) values[i]); } @@ -540,8 +539,11 @@ _ReadLOArray(char *str, if (inputfile == NULL) elog(ERROR, "array_in: missing file name"); - lobjId = lo_creat(0); - *fd = lo_open(lobjId, INV_READ); + 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; @@ -551,11 +553,7 @@ _ReadLOArray(char *str, { FILE *afd; -#ifndef __CYGWIN32__ - if ((afd = AllocateFile(accessfile, "r")) == NULL) -#else - if ((afd = AllocateFile(accessfile, "r")) == NULL) -#endif + 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, @@ -581,7 +579,7 @@ _CopyArrayEls(char **values, { int inc; - inc = ArrayCastAndSet(values[i], typbyval, typlen, p); + inc = ArrayCastAndSet((Datum) values[i], typbyval, typlen, p); p += inc; if (!typbyval) pfree(values[i]); @@ -595,9 +593,11 @@ _CopyArrayEls(char **values, * containing the array in its external format. *------------------------------------------------------------------------- */ -char * -array_out(ArrayType *v, Oid element_type) +Datum +array_out(PG_FUNCTION_ARGS) { + ArrayType *v = (ArrayType *) PG_GETARG_VARLENA_P(0); + Oid element_type = PG_GETARG_OID(1); int typlen; bool typbyval; char typdelim; @@ -605,7 +605,6 @@ array_out(ArrayType *v, Oid element_type) typelem; FmgrInfo outputproc; char typalign; - char *p, *tmp, *retval, @@ -620,30 +619,28 @@ array_out(ArrayType *v, Oid element_type) l, #endif indx[MAXDIM]; - bool dummy_bool; int ndim, *dim; - if (v == (ArrayType *) NULL) - return (char *) NULL; - if (ARR_IS_LO(v) == true) { - char *p, - *save_p; - int nbytes; + text *p; + int plen, + nbytes; - /* get a wide string to print to */ - p = array_dims(v, &dummy_bool); - nbytes = strlen(ARR_DATA_PTR(v)) + VARHDRSZ + *(int *) p; + p = (text *) DatumGetPointer(DirectFunctionCall1(array_dims, + PointerGetDatum(v))); + plen = VARSIZE(p) - VARHDRSZ; - save_p = (char *) palloc(nbytes); + /* get a wide string to print to */ + nbytes = strlen(ARR_DATA_PTR(v)) + strlen(ASSGN) + plen + 1; + retval = (char *) palloc(nbytes); - strcpy(save_p, p + sizeof(int)); - strcat(save_p, ASSGN); - strcat(save_p, ARR_DATA_PTR(v)); + memcpy(retval, VARDATA(p), plen); + strcpy(retval + plen, ASSGN); + strcat(retval, ARR_DATA_PTR(v)); pfree(p); - return save_p; + PG_RETURN_CSTRING(retval); } system_cache_lookup(element_type, false, &typlen, &typbyval, @@ -656,12 +653,11 @@ array_out(ArrayType *v, Oid element_type) if (nitems == 0) { - char *emptyArray = palloc(3); - - emptyArray[0] = '{'; - emptyArray[1] = '}'; - emptyArray[2] = '\0'; - return emptyArray; + retval = (char *) palloc(3); + retval[0] = '{'; + retval[1] = '}'; + retval[2] = '\0'; + PG_RETURN_CSTRING(retval); } p = ARR_DATA_PTR(v); @@ -674,21 +670,33 @@ array_out(ArrayType *v, Oid element_type) switch (typlen) { case 1: - values[i] = (*fmgr_faddr(&outputproc)) (*p, typelem); + values[i] = DatumGetCString(FunctionCall3(&outputproc, + CharGetDatum(*p), + ObjectIdGetDatum(typelem), + Int32GetDatum(-1))); break; case 2: - values[i] = (*fmgr_faddr(&outputproc)) (*(int16 *) p, typelem); + values[i] = DatumGetCString(FunctionCall3(&outputproc, + Int16GetDatum(*(int16 *) p), + ObjectIdGetDatum(typelem), + Int32GetDatum(-1))); break; case 3: case 4: - values[i] = (*fmgr_faddr(&outputproc)) (*(int32 *) p, typelem); + values[i] = DatumGetCString(FunctionCall3(&outputproc, + Int32GetDatum(*(int32 *) p), + ObjectIdGetDatum(typelem), + Int32GetDatum(-1))); break; } p += typlen; } else { - values[i] = (*fmgr_faddr(&outputproc)) (p, typelem); + values[i] = DatumGetCString(FunctionCall3(&outputproc, + PointerGetDatum(p), + ObjectIdGetDatum(typelem), + Int32GetDatum(-1))); if (typlen > 0) p += typlen; else @@ -767,58 +775,61 @@ array_out(ArrayType *v, Oid element_type) } while (j != -1); pfree(values); - return retval; + PG_RETURN_CSTRING(retval); } /*----------------------------------------------------------------------------- * array_dims : - * returns the dimension of the array pointed to by "v" + * returns the dimensions of the array pointed to by "v", as a "text" *---------------------------------------------------------------------------- */ -char * -array_dims(ArrayType *v, bool *isNull) +Datum +array_dims(PG_FUNCTION_ARGS) { - char *p, - *save_p; + ArrayType *v = (ArrayType *) PG_GETARG_VARLENA_P(0); + text *result; + char *p; int nbytes, i; int *dimv, *lb; - if (v == (ArrayType *) NULL) - RETURN_NULL; - nbytes = ARR_NDIM(v) * 33; - + nbytes = ARR_NDIM(v) * 33 + 1; /* * 33 since we assume 15 digits per number + ':' +'[]' + * + * +1 allows for temp trailing null */ - save_p = p = (char *) palloc(nbytes + VARHDRSZ); - MemSet(save_p, 0, nbytes + VARHDRSZ); + + result = (text *) palloc(nbytes + VARHDRSZ); + MemSet(result, 0, nbytes + VARHDRSZ); + p = VARDATA(result); + dimv = ARR_DIMS(v); lb = ARR_LBOUND(v); - p += VARHDRSZ; + for (i = 0; i < ARR_NDIM(v); i++) { sprintf(p, "[%d:%d]", lb[i], dimv[i] + lb[i] - 1); p += strlen(p); } - nbytes = strlen(save_p + VARHDRSZ) + VARHDRSZ; - memmove(save_p, &nbytes, VARHDRSZ); - return save_p; + VARSIZE(result) = strlen(VARDATA(result)) + VARHDRSZ; + + PG_RETURN_TEXT_P(result); } /*--------------------------------------------------------------------------- * array_ref : - * This routing takes an array pointer and an index array and returns + * This routine takes an array pointer and an index array and returns * a pointer to the referred element if element is passed by * reference otherwise returns the value of the referred element. *--------------------------------------------------------------------------- */ Datum array_ref(ArrayType *array, - int n, + int nSubscripts, int *indx, - int reftype, + bool elmbyval, int elmlen, int arraylen, bool *isNull) @@ -830,10 +841,11 @@ array_ref(ArrayType *array, offset, nbytes; struct varlena *v = NULL; - char *retval = NULL; + Datum result; + char *retval; if (array == (ArrayType *) NULL) - RETURN_NULL; + RETURN_NULL(Datum); if (arraylen > 0) { @@ -843,17 +855,17 @@ array_ref(ArrayType *array, if (indx[0] * elmlen > arraylen) elog(ERROR, "array_ref: array bound exceeded"); retval = (char *) array + indx[0] * elmlen; - return _ArrayCast(retval, reftype, elmlen); + return _ArrayCast(retval, elmbyval, elmlen); } dim = ARR_DIMS(array); lb = ARR_LBOUND(array); ndim = ARR_NDIM(array); nbytes = (*(int32 *) array) - ARR_OVERHEAD(ndim); - if (!SanityCheckInput(ndim, n, dim, lb, indx)) - RETURN_NULL; + if (!SanityCheckInput(ndim, nSubscripts, dim, lb, indx)) + RETURN_NULL(Datum); - offset = GetOffset(n, dim, lb, indx); + offset = GetOffset(nSubscripts, dim, lb, indx); if (ARR_IS_LO(array)) { @@ -865,33 +877,39 @@ array_ref(ArrayType *array, 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; + RETURN_NULL(Datum); #endif if (ARR_IS_CHUNKED(array)) v = _ReadChunkArray1El(indx, elmlen, fd, array, isNull); else { - if (lo_lseek(fd, offset, SEEK_SET) < 0) - RETURN_NULL; + if (DatumGetInt32(DirectFunctionCall3(lo_lseek, + Int32GetDatum(fd), + Int32GetDatum(offset), + Int32GetDatum(SEEK_SET))) < 0) + RETURN_NULL(Datum); #ifdef LOARRAY - v = (struct varlena *) LOread(fd, elmlen); + v = (struct varlena *) + DatumGetPointer(DirectFunctionCall2(loread, + Int32GetDatum(fd), + Int32GetDatum(elmlen))); #endif } if (*isNull) - RETURN_NULL; + RETURN_NULL(Datum); if (VARSIZE(v) - VARHDRSZ < elmlen) - RETURN_NULL; - lo_close(fd); - retval = (char *) _ArrayCast((char *) VARDATA(v), reftype, elmlen); - if (reftype == 0) + RETURN_NULL(Datum); + DirectFunctionCall1(lo_close, Int32GetDatum(fd)); + result = _ArrayCast((char *) VARDATA(v), elmbyval, elmlen); + if (! elmbyval) { /* not by value */ char *tempdata = palloc(elmlen); - memmove(tempdata, retval, elmlen); - retval = tempdata; + memmove(tempdata, DatumGetPointer(result), elmlen); + result = PointerGetDatum(tempdata); } pfree(v); - return (Datum) retval; + return result; } if (elmlen > 0) @@ -899,32 +917,25 @@ array_ref(ArrayType *array, offset = offset * elmlen; /* off the end of the array */ if (nbytes - offset < 1) - RETURN_NULL; + RETURN_NULL(Datum); retval = ARR_DATA_PTR(array) + offset; - return _ArrayCast(retval, reftype, elmlen); + return _ArrayCast(retval, elmbyval, elmlen); } else { - bool done = false; - char *temp; int bytes = nbytes; - temp = ARR_DATA_PTR(array); + retval = ARR_DATA_PTR(array); i = 0; - while (bytes > 0 && !done) + while (bytes > 0) { if (i == offset) - { - retval = temp; - done = true; - } - bytes -= INTALIGN(*(int32 *) temp); - temp += INTALIGN(*(int32 *) temp); + return PointerGetDatum(retval); + bytes -= INTALIGN(*(int32 *) retval); + retval += INTALIGN(*(int32 *) retval); i++; } - if (!done) - RETURN_NULL; - return (Datum) retval; + RETURN_NULL(Datum); } } @@ -935,13 +946,13 @@ array_ref(ArrayType *array, * and returns a pointer to it. *----------------------------------------------------------------------------- */ -Datum +ArrayType * array_clip(ArrayType *array, - int n, + int nSubscripts, int *upperIndx, int *lowerIndx, - int reftype, - int len, + bool elmbyval, + int elmlen, bool *isNull) { int i, @@ -955,22 +966,20 @@ array_clip(ArrayType *array, /* timer_start(); */ if (array == (ArrayType *) NULL) - RETURN_NULL; + RETURN_NULL(ArrayType *); dim = ARR_DIMS(array); lb = ARR_LBOUND(array); ndim = ARR_NDIM(array); nbytes = (*(int32 *) array) - ARR_OVERHEAD(ndim); - if (!SanityCheckInput(ndim, n, dim, lb, upperIndx)) - RETURN_NULL; - - if (!SanityCheckInput(ndim, n, dim, lb, lowerIndx)) - RETURN_NULL; + if (!SanityCheckInput(ndim, nSubscripts, dim, lb, upperIndx) || + !SanityCheckInput(ndim, nSubscripts, dim, lb, lowerIndx)) + RETURN_NULL(ArrayType *); - for (i = 0; i < n; i++) + for (i = 0; i < nSubscripts; i++) if (lowerIndx[i] > upperIndx[i]) elog(ERROR, "lowerIndex cannot be larger than upperIndx"); - mda_get_range(n, span, lowerIndx, upperIndx); + mda_get_range(nSubscripts, span, lowerIndx, upperIndx); if (ARR_IS_LO(array)) { @@ -984,23 +993,23 @@ array_clip(ArrayType *array, isDestLO = true, rsize; - if (len < 0) - elog(ERROR, "array_clip: array of variable length objects not supported"); + 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; + RETURN_NULL(ArrayType *); newname = _array_newLO(&newfd, Unix); #endif - bytes = strlen(newname) + 1 + ARR_OVERHEAD(n); + bytes = strlen(newname) + 1 + ARR_OVERHEAD(nSubscripts); newArr = (ArrayType *) palloc(bytes); memmove(newArr, array, sizeof(ArrayType)); memmove(newArr, &bytes, sizeof(int)); - memmove(ARR_DIMS(newArr), span, n * sizeof(int)); - memmove(ARR_LBOUND(newArr), lowerIndx, n * sizeof(int)); + memmove(ARR_DIMS(newArr), span, nSubscripts * sizeof(int)); + memmove(ARR_LBOUND(newArr), lowerIndx, nSubscripts * sizeof(int)); strcpy(ARR_DATA_PTR(newArr), newname); - rsize = compute_size(lowerIndx, upperIndx, n, len); + rsize = compute_size(lowerIndx, upperIndx, nSubscripts, elmlen); if (rsize < MAX_BUFF_SIZE) { char *buff; @@ -1011,19 +1020,21 @@ array_clip(ArrayType *array, isDestLO = false; if (ARR_IS_CHUNKED(array)) { - _ReadChunkArray(lowerIndx, upperIndx, len, fd, &(buff[VARHDRSZ]), + _ReadChunkArray(lowerIndx, upperIndx, elmlen, fd, &(buff[VARHDRSZ]), array, 0, isNull); } else { - _ReadArray(lowerIndx, upperIndx, len, fd, (int) &(buff[VARHDRSZ]), + _ReadArray(lowerIndx, upperIndx, elmlen, fd, (int) &(buff[VARHDRSZ]), array, 0, isNull); } memmove(buff, &rsize, VARHDRSZ); #ifdef LOARRAY if (!*isNull) - bytes = LOwrite(newfd, (struct varlena *) buff); + bytes = DatumGetInt32(DirectFunctionCall2(lowrite, + Int32GetDatum(newfd), + PointerGetDatum(buff))); #endif pfree(buff); } @@ -1031,11 +1042,11 @@ array_clip(ArrayType *array, { if (ARR_IS_CHUNKED(array)) { - _ReadChunkArray(lowerIndx, upperIndx, len, fd, (char *) newfd, array, + _ReadChunkArray(lowerIndx, upperIndx, elmlen, fd, (char *) newfd, array, 1, isNull); } else - _ReadArray(lowerIndx, upperIndx, len, fd, newfd, array, 1, isNull); + _ReadArray(lowerIndx, upperIndx, elmlen, fd, newfd, array, 1, isNull); } #ifdef LOARRAY LOclose(fd); @@ -1047,42 +1058,42 @@ array_clip(ArrayType *array, newArr = NULL; } /* timer_end(); */ - return (Datum) newArr; + return newArr; } - if (len > 0) + if (elmlen > 0) { - bytes = getNitems(n, span); - bytes = bytes * len + ARR_OVERHEAD(n); + bytes = getNitems(nSubscripts, span); + bytes = bytes * elmlen + ARR_OVERHEAD(nSubscripts); } else { bytes = _ArrayClipCount(lowerIndx, upperIndx, array); - bytes += ARR_OVERHEAD(n); + bytes += ARR_OVERHEAD(nSubscripts); } newArr = (ArrayType *) palloc(bytes); memmove(newArr, array, sizeof(ArrayType)); memmove(newArr, &bytes, sizeof(int)); - memmove(ARR_DIMS(newArr), span, n * sizeof(int)); - memmove(ARR_LBOUND(newArr), lowerIndx, n * sizeof(int)); - _ArrayRange(lowerIndx, upperIndx, len, ARR_DATA_PTR(newArr), array, 1); - return (Datum) newArr; + memmove(ARR_DIMS(newArr), span, nSubscripts * sizeof(int)); + memmove(ARR_LBOUND(newArr), lowerIndx, nSubscripts * sizeof(int)); + _ArrayRange(lowerIndx, upperIndx, elmlen, ARR_DATA_PTR(newArr), array, 1); + return newArr; } /*----------------------------------------------------------------------------- * array_set : - * This routine sets the value of an array location (specified by an index array) - * to a new value specified by "dataPtr". + * 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. *----------------------------------------------------------------------------- */ -char * +ArrayType * array_set(ArrayType *array, - int n, + int nSubscripts, int *indx, - char *dataPtr, - int reftype, + Datum dataValue, + bool elmbyval, int elmlen, int arraylen, bool *isNull) @@ -1095,7 +1106,7 @@ array_set(ArrayType *array, char *pos; if (array == (ArrayType *) NULL) - RETURN_NULL; + RETURN_NULL(ArrayType *); if (arraylen > 0) { @@ -1105,20 +1116,20 @@ array_set(ArrayType *array, if (indx[0] * elmlen > arraylen) elog(ERROR, "array_ref: array bound exceeded"); pos = (char *) array + indx[0] * elmlen; - ArrayCastAndSet(dataPtr, (bool) reftype, elmlen, pos); - return (char *) array; + ArrayCastAndSet(dataValue, elmbyval, elmlen, pos); + return array; } dim = ARR_DIMS(array); lb = ARR_LBOUND(array); ndim = ARR_NDIM(array); nbytes = (*(int32 *) array) - ARR_OVERHEAD(ndim); - if (!SanityCheckInput(ndim, n, dim, lb, indx)) + if (!SanityCheckInput(ndim, nSubscripts, dim, lb, indx)) { elog(ERROR, "array_set: array bound exceeded"); - return (char *) array; + return array; } - offset = GetOffset(n, dim, lb, indx); + offset = GetOffset(nSubscripts, dim, lb, indx); if (ARR_IS_LO(array)) { @@ -1132,30 +1143,33 @@ array_set(ArrayType *array, lo_name = ARR_DATA_PTR(array); if ((fd = LOopen(lo_name, ARR_IS_INV(array) ? INV_WRITE : O_WRONLY)) < 0) - return (char *) array; + return array; #endif - if (lo_lseek(fd, offset, SEEK_SET) < 0) - return (char *) array; + if (DatumGetInt32(DirectFunctionCall3(lo_lseek, + Int32GetDatum(fd), + Int32GetDatum(offset), + Int32GetDatum(SEEK_SET))) < 0) + return array; v = (struct varlena *) palloc(elmlen + VARHDRSZ); VARSIZE(v) = elmlen + VARHDRSZ; - ArrayCastAndSet(dataPtr, (bool) reftype, elmlen, VARDATA(v)); + ArrayCastAndSet(dataValue, elmbyval, elmlen, VARDATA(v)); #ifdef LOARRAY - n = LOwrite(fd, v); + if (DatumGetInt32(DirectFunctionCall2(lowrite, + Int32GetDatum(fd), + PointerGetDatum(v))) + != elmlen) + RETURN_NULL(ArrayType *); #endif - - /* - * if (n < VARSIZE(v) - VARHDRSZ) RETURN_NULL; - */ pfree(v); - lo_close(fd); - return (char *) array; + DirectFunctionCall1(lo_close, Int32GetDatum(fd)); + return array; } if (elmlen > 0) { offset = offset * elmlen; /* off the end of the array */ if (nbytes - offset < 1) - return (char *) array; + return array; pos = ARR_DATA_PTR(array) + offset; } else @@ -1172,18 +1186,18 @@ array_set(ArrayType *array, elt_ptr = array_seek(ARR_DATA_PTR(array), -1, offset); oldlen = INTALIGN(*(int32 *) elt_ptr); - newlen = INTALIGN(*(int32 *) dataPtr); + newlen = INTALIGN(*(int32 *) DatumGetPointer(dataValue)); if (oldlen == newlen) { /* new element with same size, overwrite old data */ - ArrayCastAndSet(dataPtr, (bool) reftype, elmlen, elt_ptr); - return (char *) array; + ArrayCastAndSet(dataValue, elmbyval, elmlen, elt_ptr); + return array; } /* new element with different size, reallocate the array */ oldsize = array->size; - lth0 = ARR_OVERHEAD(n); + lth0 = ARR_OVERHEAD(nSubscripts); lth1 = (int) (elt_ptr - ARR_DATA_PTR(array)); lth2 = (int) (oldsize - lth0 - lth1 - oldlen); newsize = lth0 + lth1 + newlen + lth2; @@ -1191,16 +1205,16 @@ array_set(ArrayType *array, newarray = (ArrayType *) palloc(newsize); memmove((char *) newarray, (char *) array, lth0 + lth1); newarray->size = newsize; - newlen = ArrayCastAndSet(dataPtr, (bool) reftype, elmlen, + 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 (char *) newarray; + return newarray; } - ArrayCastAndSet(dataPtr, (bool) reftype, elmlen, pos); - return (char *) array; + ArrayCastAndSet(dataValue, elmbyval, elmlen, pos); + return array; } /*---------------------------------------------------------------------------- @@ -1212,14 +1226,14 @@ array_set(ArrayType *array, * returns a pointer to the modified array. *---------------------------------------------------------------------------- */ -char * +ArrayType * array_assgn(ArrayType *array, - int n, + int nSubscripts, int *upperIndx, int *lowerIndx, ArrayType *newArr, - int reftype, - int len, + bool elmbyval, + int elmlen, bool *isNull) { int i, @@ -1228,19 +1242,19 @@ array_assgn(ArrayType *array, *lb; if (array == (ArrayType *) NULL) - RETURN_NULL; - if (len < 0) - elog(ERROR, "array_assgn:updates on arrays of variable length elements not allowed"); + RETURN_NULL(ArrayType *); + if (elmlen < 0) + elog(ERROR, "array_assgn: updates on arrays of variable length elements not implemented"); dim = ARR_DIMS(array); lb = ARR_LBOUND(array); ndim = ARR_NDIM(array); - if (!SanityCheckInput(ndim, n, dim, lb, upperIndx) || - !SanityCheckInput(ndim, n, dim, lb, lowerIndx)) - return (char *) array; + if (!SanityCheckInput(ndim, nSubscripts, dim, lb, upperIndx) || + !SanityCheckInput(ndim, nSubscripts, dim, lb, lowerIndx)) + RETURN_NULL(ArrayType *); - for (i = 0; i < n; i++) + for (i = 0; i < nSubscripts; i++) if (lowerIndx[i] > upperIndx[i]) elog(ERROR, "lowerIndex larger than upperIndx"); @@ -1254,49 +1268,63 @@ array_assgn(ArrayType *array, lo_name = (char *) ARR_DATA_PTR(array); if ((fd = LOopen(lo_name, ARR_IS_INV(array) ? INV_WRITE : O_WRONLY)) < 0) - return (char *) array; + 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 (char *) array; + return array; #endif - _LOArrayRange(lowerIndx, upperIndx, len, fd, newfd, array, 1, isNull); - lo_close(newfd); + _LOArrayRange(lowerIndx, upperIndx, elmlen, fd, newfd, array, 1, isNull); + DirectFunctionCall1(lo_close, Int32GetDatum(newfd)); } else { - _LOArrayRange(lowerIndx, upperIndx, len, fd, (int) ARR_DATA_PTR(newArr), + _LOArrayRange(lowerIndx, upperIndx, elmlen, fd, (int) ARR_DATA_PTR(newArr), array, 0, isNull); } - lo_close(fd); - return (char *) array; + DirectFunctionCall1(lo_close, Int32GetDatum(fd)); + return array; } - _ArrayRange(lowerIndx, upperIndx, len, ARR_DATA_PTR(newArr), array, 0); - return (char *) array; + _ArrayRange(lowerIndx, upperIndx, elmlen, ARR_DATA_PTR(newArr), array, 0); + return array; } /* * array_map() * - * Map an arbitrary function to an array and return a new array with - * same dimensions and the source elements transformed by fn(). + * Map an array through an arbitrary function. Return a new array with + * same dimensions and each source element transformed by fn(). Each + * source element is passed as the first argument to fn(); additional + * arguments to be passed to fn() can be specified by the caller. + * The output array can have a different element type than the input. + * + * Parameters are: + * * fcinfo: a function-call data structure pre-constructed by the caller + * to be ready to call the desired function, with everything except the + * first argument position filled in. In particular, flinfo identifies + * the function fn(), and if nargs > 1 then argument positions after the + * first must be preset to the additional values to be passed. The + * first argument position initially holds the input array value. + * * inpType: OID of element type of input array. This must be the same as, + * or binary-compatible with, the first argument type of fn(). + * * retType: OID of element type of output array. This must be the same as, + * or binary-compatible with, the result type of fn(). + * + * NB: caller must assure that input array is not NULL. Currently, + * any additional parameters passed to fn() may not be specified as NULL + * either. */ -ArrayType * -array_map(ArrayType *v, - Oid type, - char *(fn)(char *p, ...), - Oid retType, - int nargs, - ...) +Datum +array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType) { - ArrayType *result; - void *args[4]; - char **values; - char *elt; - int *dim; + ArrayType *v; + ArrayType *result; + char **values; + char *elt; + int *dim; int ndim; int nitems; int i; @@ -1308,105 +1336,103 @@ array_map(ArrayType *v, char typdelim; Oid typelem; Oid proc; - char typalign; - char *s; - char *p; - va_list ap; + char typalign; + char *s; + char *p; + + /* Get input array */ + if (fcinfo->nargs < 1) + elog(ERROR, "array_map: invalid nargs: %d", fcinfo->nargs); + if (PG_ARGISNULL(0)) + elog(ERROR, "array_map: null input array"); + v = (ArrayType *) PG_GETARG_VARLENA_P(0); /* Large objects not yet supported */ - if (ARR_IS_LO(v) == true) { + if (ARR_IS_LO(v) == true) elog(ERROR, "array_map: large objects not supported"); - } - /* Check nargs */ - if ((nargs < 0) || (nargs > 4)) { - elog(ERROR, "array_map: invalid nargs: %d", nargs); - } + ndim = ARR_NDIM(v); + dim = ARR_DIMS(v); + nitems = getNitems(ndim, dim); - /* Copy extra args to local variable */ - va_start(ap, nargs); - for (i=0; i 0) { + if (inp_typlen > 0) s += inp_typlen; - } else { + else s += INTALIGN(*(int32 *) s); - } } /* * Apply the given function to source elt and extra args. - * nargs is the number of extra args taken by fn(). + * + * We assume the extra args are non-NULL, so need not check + * whether fn() is strict. Would need to do more work here + * to support arrays containing nulls, too. */ - switch (nargs) { - case 0: - p = (char *) (*fn) (elt); - break; - case 1: - p = (char *) (*fn) (elt, args[0]); - break; - case 2: - p = (char *) (*fn) (elt, args[0], args[1]); - break; - case 3: - p = (char *) (*fn) (elt, args[0], args[1], args[2]); - break; - case 4: - default: - p = (char *) (*fn) (elt, args[0], args[1], args[2], args[3]); - break; - } + fcinfo->arg[0] = (Datum) elt; + fcinfo->argnull[0] = false; + fcinfo->isnull = false; + p = (char *) FunctionCallInvoke(fcinfo); + if (fcinfo->isnull) + elog(ERROR, "array_map: cannot handle NULL in array"); /* Update values and total result size */ - if (typbyval) { - values[i] = (char *) p; + if (typbyval) + { + values[i] = p; nbytes += typlen; - } else { - int len; + } + else + { + int len; + len = ((typlen > 0) ? typlen : INTALIGN(*(int32 *) p)); /* Needed because _CopyArrayEls tries to pfree items */ - if (p == elt) { + if (p == elt) + { p = (char *) palloc(len); memcpy(p, elt, len); } - values[i] = (char *) p; + values[i] = p; nbytes += len; } } @@ -1425,26 +1451,27 @@ array_map(ArrayType *v, ARR_DATA_PTR(result), nitems, typlen, typalign, typbyval); - return result; + PG_RETURN_POINTER(result); } /*----------------------------------------------------------------------------- * array_eq : * compares two arrays for equality * result : - * returns 1 if the arrays are equal, 0 otherwise. + * returns true if the arrays are equal, false otherwise. *----------------------------------------------------------------------------- */ -int -array_eq(ArrayType *array1, ArrayType *array2) +Datum +array_eq(PG_FUNCTION_ARGS) { - if ((array1 == NULL) || (array2 == NULL)) - return 0; - if (*(int *) array1 != *(int *) array2) - return 0; - if (memcmp(array1, array2, *(int *) array1)) - return 0; - return 1; + ArrayType *array1 = (ArrayType *) PG_GETARG_VARLENA_P(0); + ArrayType *array2 = (ArrayType *) PG_GETARG_VARLENA_P(1); + + if (*(int32 *) array1 != *(int32 *) array2) + PG_RETURN_BOOL(false); + if (memcmp(array1, array2, *(int32 *) array1) != 0) + PG_RETURN_BOOL(false); + PG_RETURN_BOOL(true); } /***************************************************************************/ @@ -1463,13 +1490,13 @@ system_cache_lookup(Oid element_type, HeapTuple typeTuple; Form_pg_type typeStruct; - typeTuple = SearchSysCacheTuple(TYPOID, + typeTuple = SearchSysCacheTuple(TYPEOID, ObjectIdGetDatum(element_type), 0, 0, 0); if (!HeapTupleIsValid(typeTuple)) { - elog(ERROR, "array_out: Cache lookup failed for type %d\n", + elog(ERROR, "array_out: Cache lookup failed for type %u\n", element_type); return; } @@ -1511,7 +1538,7 @@ _ArrayCast(char *value, bool byval, int len) static int -ArrayCastAndSet(char *src, +ArrayCastAndSet(Datum src, bool typbyval, int typlen, char *dest) @@ -1531,18 +1558,18 @@ ArrayCastAndSet(char *src, *(int16 *) dest = DatumGetInt16(src); break; case 4: - *(int32 *) dest = (int32) src; + *(int32 *) dest = DatumGetInt32(src); break; } } else - memmove(dest, src, typlen); + memmove(dest, DatumGetPointer(src), typlen); inc = typlen; } else { - memmove(dest, src, *(int32 *) src); - inc = (INTALIGN(*(int32 *) src)); + memmove(dest, DatumGetPointer(src), *(int32 *) DatumGetPointer(src)); + inc = (INTALIGN(*(int32 *) DatumGetPointer(src))); } return inc; } @@ -1740,7 +1767,10 @@ _LOArrayRange(int *st, mda_get_prod(n, dim, prod); st_pos = tuple2linear(n, st, prod); offset = st_pos * bsize; - if (lo_lseek(srcfd, offset, SEEK_SET) < 0) + 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); @@ -1752,7 +1782,10 @@ _LOArrayRange(int *st, do { offset += (dist[j] * bsize); - if (lo_lseek(srcfd, offset, SEEK_SET) < 0) + 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) @@ -1794,7 +1827,10 @@ _ReadArray(int *st, mda_get_prod(n, dim, prod); st_pos = tuple2linear(n, st, prod); offset = st_pos * bsize; - if (lo_lseek(srcfd, offset, SEEK_SET) < 0) + 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); @@ -1806,7 +1842,10 @@ _ReadArray(int *st, do { offset += (dist[j] * bsize); - if (lo_lseek(srcfd, offset, SEEK_SET) < 0) + 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) @@ -1825,7 +1864,9 @@ _LOtransfer(char **destfd, 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, @@ -1837,13 +1878,18 @@ _LOtransfer(char **destfd, resid > 0 && (inc = min(resid, MAX_READ)) > 0; resid -= inc) { #ifdef LOARRAY - v = (struct varlena *) LOread((int) *srcfd, inc); + v = (struct varlena *) + DatumGetPointer(DirectFunctionCall2(loread, + Int32GetDatum((int32) *srcfd), + Int32GetDatum(inc))); if (VARSIZE(v) - VARHDRSZ < inc) { pfree(v); return -1; } - tmp += LOwrite((int) *destfd, v); + tmp += DatumGetInt32(DirectFunctionCall2(lowrite, + Int32GetDatum((int32) *destfd), + PointerGetDatum(v))); #endif pfree(v); @@ -1876,7 +1922,7 @@ _array_newLO(int *fd, int flag) char saveName[NAME_LEN]; p = (char *) palloc(NAME_LEN); - sprintf(p, "/Arry.%d", newoid()); + sprintf(p, "/Arry.%u", newoid()); strcpy(saveName, p); #ifdef LOARRAY if ((*fd = LOcreat(saveName, 0600, flag)) < 0)