diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c index acb4e8f48a..bd9ab6c60e 100644 --- a/src/backend/utils/adt/arrayfuncs.c +++ b/src/backend/utils/adt/arrayfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.52 2000/01/26 05:57:12 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.53 2000/05/29 21:02:32 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -17,7 +17,6 @@ #include "postgres.h" - #include "catalog/catalog.h" #include "catalog/pg_type.h" #include "fmgr.h" @@ -1277,19 +1276,33 @@ array_assgn(ArrayType *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) (), - Oid retType, - int nargs, - ...) +Datum +array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType) { + ArrayType *v; ArrayType *result; - void *args[4]; char **values; char *elt; int *dim; @@ -1307,35 +1320,31 @@ array_map(ArrayType *v, char typalign; char *s; char *p; - va_list ap; + + /* 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_POINTER(0); /* Large objects not yet supported */ 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); - - /* Copy extra args to local variable */ - va_start(ap, nargs); - for (i = 0; i < nargs; i++) - args[i] = (void *) va_arg(ap, char *); - va_end(ap); - - /* Lookup source and result types. Unneeded variables are reused. */ - system_cache_lookup(type, false, &inp_typlen, &inp_typbyval, - &typdelim, &typelem, &proc, &typalign); - system_cache_lookup(retType, false, &typlen, &typbyval, - &typdelim, &typelem, &proc, &typalign); - ndim = ARR_NDIM(v); dim = ARR_DIMS(v); nitems = getNitems(ndim, dim); /* Check for empty array */ if (nitems <= 0) - return v; + PG_RETURN_POINTER(v); + + /* Lookup source and result types. Unneeded variables are reused. */ + system_cache_lookup(inpType, false, &inp_typlen, &inp_typbyval, + &typdelim, &typelem, &proc, &typalign); + system_cache_lookup(retType, false, &typlen, &typbyval, + &typdelim, &typelem, &proc, &typalign); /* Allocate temporary array for new values */ values = (char **) palloc(nitems * sizeof(char *)); @@ -1374,33 +1383,23 @@ array_map(ArrayType *v, } /* - * Apply the given function to source elt and extra args. nargs is - * the number of extra args taken by fn(). + * Apply the given function to source elt and extra args. + * + * 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; + values[i] = p; nbytes += typlen; } else @@ -1414,7 +1413,7 @@ array_map(ArrayType *v, p = (char *) palloc(len); memcpy(p, elt, len); } - values[i] = (char *) p; + values[i] = p; nbytes += len; } } @@ -1433,7 +1432,7 @@ array_map(ArrayType *v, ARR_DATA_PTR(result), nitems, typlen, typalign, typbyval); - return result; + PG_RETURN_POINTER(result); } /*----------------------------------------------------------------------------- diff --git a/src/backend/utils/adt/varchar.c b/src/backend/utils/adt/varchar.c index 0837b8b63a..67ff10cc07 100644 --- a/src/backend/utils/adt/varchar.c +++ b/src/backend/utils/adt/varchar.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/varchar.c,v 1.60 2000/04/12 17:15:52 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/varchar.c,v 1.61 2000/05/29 21:02:32 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -17,6 +17,7 @@ #include "access/htup.h" #include "catalog/pg_type.h" #include "utils/builtins.h" +#include "utils/fmgroids.h" #ifdef MULTIBYTE #include "mb/pg_wchar.h" @@ -206,7 +207,26 @@ bpchar(char *s, int32 len) ArrayType * _bpchar(ArrayType *v, int32 len) { - return array_map(v, BPCHAROID, bpchar, BPCHAROID, 1, len); + FunctionCallInfoData locfcinfo; + Datum result; + /* Since bpchar() is a built-in function, we should only need to + * look it up once per run. + */ + static FmgrInfo bpchar_finfo; + + if (bpchar_finfo.fn_oid == InvalidOid) + fmgr_info(F_BPCHAR, &bpchar_finfo); + + MemSet(&locfcinfo, 0, sizeof(locfcinfo)); + locfcinfo.flinfo = &bpchar_finfo; + locfcinfo.nargs = 2; + /* We assume we are "strict" and need not worry about null inputs */ + locfcinfo.arg[0] = PointerGetDatum(v); + locfcinfo.arg[1] = Int32GetDatum(len); + + result = array_map(&locfcinfo, BPCHAROID, BPCHAROID); + + return (ArrayType *) DatumGetPointer(result); } @@ -409,7 +429,26 @@ varchar(char *s, int32 slen) ArrayType * _varchar(ArrayType *v, int32 len) { - return array_map(v, VARCHAROID, varchar, VARCHAROID, 1, len); + FunctionCallInfoData locfcinfo; + Datum result; + /* Since varchar() is a built-in function, we should only need to + * look it up once per run. + */ + static FmgrInfo varchar_finfo; + + if (varchar_finfo.fn_oid == InvalidOid) + fmgr_info(F_VARCHAR, &varchar_finfo); + + MemSet(&locfcinfo, 0, sizeof(locfcinfo)); + locfcinfo.flinfo = &varchar_finfo; + locfcinfo.nargs = 2; + /* We assume we are "strict" and need not worry about null inputs */ + locfcinfo.arg[0] = PointerGetDatum(v); + locfcinfo.arg[1] = Int32GetDatum(len); + + result = array_map(&locfcinfo, VARCHAROID, VARCHAROID); + + return (ArrayType *) DatumGetPointer(result); } diff --git a/src/include/utils/array.h b/src/include/utils/array.h index 61317d4705..c48baa974f 100644 --- a/src/include/utils/array.h +++ b/src/include/utils/array.h @@ -1,7 +1,7 @@ /*------------------------------------------------------------------------- * * array.h - * Utilities for the new array code. Contain prototypes from the + * Utilities for the new array code. Contains prototypes from the * following files: * utils/adt/arrayfuncs.c * utils/adt/arrayutils.c @@ -11,18 +11,19 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: array.h,v 1.23 2000/04/12 17:16:54 momjian Exp $ + * $Id: array.h,v 1.24 2000/05/29 21:02:32 tgl Exp $ * * NOTES - * XXX the data array should be LONGALIGN'd -- notice that the array + * 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 LONGALIGNs. + * even though the array-packing code does the MAXALIGNs. * *------------------------------------------------------------------------- */ #ifndef ARRAY_H #define ARRAY_H +#include "fmgr.h" #include "utils/memutils.h" typedef struct @@ -123,9 +124,7 @@ extern char *array_set(ArrayType *array, int n, int *indx, char *dataPtr, extern char *array_assgn(ArrayType *array, int n, int *upperIndx, int *lowerIndx, ArrayType *newArr, int reftype, int len, bool *isNull); -extern ArrayType *array_map(ArrayType *v, Oid type, - char *(*fn) (), - Oid retType, int nargs,...); +extern Datum array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType); extern int array_eq(ArrayType *array1, ArrayType *array2); extern int _LOtransfer(char **destfd, int size, int nitems, char **srcfd, int isSrcLO, int isDestLO);