diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c
index acb4e8f48a2df3ca8673aeab22f87197c4c76b5b..bd9ab6c60e75ec206f829262f5f0f243fa577168 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 0837b8b63a1ba0ed958d98fa2b83b3ab012224e1..67ff10cc073d46da8cfadaf55d069dcb081af7e6 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 61317d47051ec7ad22fe1c078900166c812f379c..c48baa974f79c0ff6be3cc0ee653f2f5f96395a7 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);