I've been taking a look at this as well and came up with a slightly different approach. The attached patch is intended to go in core (not contrib) and uses some array-construction facilities that already exist in core. I'm not sure which approach is better, so I'll throw this out there with yours for input...
...Robert
Index: src/backend/utils/adt/array_userfuncs.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/array_userfuncs.c,v retrieving revision 1.23 diff -c -r1.23 array_userfuncs.c *** src/backend/utils/adt/array_userfuncs.c 1 Jan 2008 19:45:52 -0000 1.23 --- src/backend/utils/adt/array_userfuncs.c 16 Oct 2008 02:22:03 -0000 *************** *** 12,17 **** --- 12,18 ---- */ #include "postgres.h" + #include "nodes/execnodes.h" #include "utils/array.h" #include "utils/builtins.h" #include "utils/lsyscache.h" *************** *** 465,467 **** --- 466,510 ---- return construct_md_array(dvalues, NULL, ndims, dims, lbs, element_type, typlen, typbyval, typalign); } + + /* + * aggregate values into an array + */ + Datum + array_accum_trans(PG_FUNCTION_ARGS) + { + ArrayBuildState *ain, *aout; + MemoryContext *mctx; + Oid arg1_typeid = get_fn_expr_argtype(fcinfo->flinfo, 1); + + if (!(fcinfo->context && IsA(fcinfo->context, AggState))) + ereport(ERROR, + (errmsg("array_accum_trans may only be used as an aggregate"))); + mctx = ((AggState *) fcinfo->context)->aggcontext; + if (arg1_typeid == InvalidOid) + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("could not determine input data type"))); + + if (PG_ARGISNULL(0)) + ain = NULL; + else + ain = PG_GETARG_POINTER(0); + + aout = accumArrayResult(ain, PG_GETARG_DATUM(1), PG_ARGISNULL(1), + arg1_typeid, mctx); + PG_RETURN_POINTER(aout); + } + + /* + * finalize accumulated array + */ + Datum + array_accum_final(PG_FUNCTION_ARGS) + { + ArrayBuildState *astate; + + if (PG_ARGISNULL(0)) + PG_RETURN_NULL(); + astate = (ArrayBuildState *) PG_GETARG_POINTER(0); + PG_RETURN_ARRAYTYPE_P(makeArrayResult(astate, CurrentMemoryContext)); + } Index: src/include/catalog/pg_aggregate.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_aggregate.h,v retrieving revision 1.66 diff -c -r1.66 pg_aggregate.h *** src/include/catalog/pg_aggregate.h 27 Mar 2008 03:57:34 -0000 1.66 --- src/include/catalog/pg_aggregate.h 16 Oct 2008 02:22:04 -0000 *************** *** 220,225 **** --- 220,228 ---- /* xml */ DATA(insert ( 2901 xmlconcat2 - 0 142 _null_ )); + /* array */ + DATA(insert ( 2335 array_accum_trans array_accum_final 0 2281 _null_ )); + /* * prototypes for functions in pg_aggregate.c */ Index: src/include/catalog/pg_proc.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_proc.h,v retrieving revision 1.520 diff -c -r1.520 pg_proc.h *** src/include/catalog/pg_proc.h 14 Oct 2008 17:12:33 -0000 1.520 --- src/include/catalog/pg_proc.h 16 Oct 2008 02:22:13 -0000 *************** *** 1017,1022 **** --- 1017,1024 ---- DESCR("array constructor with value"); DATA(insert OID = 1286 ( array_fill PGNSP PGUID 12 1 0 0 f f f f i 3 2277 "2283 1007 1007" _null_ _null_ _null_ array_fill_with_lower_bounds _null_ _null_ _null_ )); DESCR("array constructor with value"); + DATA(insert OID = 2333 ( array_accum_trans PGNSP PGUID 12 1 0 0 f f f f i 2 2281 "2281 2283" _null_ _null_ _null_ array_accum_trans _null_ _null_ _null_ )); + DATA(insert OID = 2334 ( array_accum_final PGNSP PGUID 12 1 0 0 f f f f i 1 2277 "2281" _null_ _null_ _null_ array_accum_final _null_ _null_ _null_ )); DATA(insert OID = 760 ( smgrin PGNSP PGUID 12 1 0 0 f f t f s 1 210 "2275" _null_ _null_ _null_ smgrin _null_ _null_ _null_ )); DESCR("I/O"); DATA(insert OID = 761 ( smgrout PGNSP PGUID 12 1 0 0 f f t f s 1 2275 "210" _null_ _null_ _null_ smgrout _null_ _null_ _null_ )); *************** *** 3439,3444 **** --- 3441,3448 ---- DATA(insert OID = 2829 ( corr PGNSP PGUID 12 1 0 0 t f f f i 2 701 "701 701" _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ )); DESCR("correlation coefficient"); + DATA(insert OID = 2335 ( array_accum PGNSP PGUID 12 1 0 0 t f f f i 1 2277 "2283" _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ )); + DATA(insert OID = 2160 ( text_pattern_lt PGNSP PGUID 12 1 0 0 f f t f i 2 16 "25 25" _null_ _null_ _null_ text_pattern_lt _null_ _null_ _null_ )); DATA(insert OID = 2161 ( text_pattern_le PGNSP PGUID 12 1 0 0 f f t f i 2 16 "25 25" _null_ _null_ _null_ text_pattern_le _null_ _null_ _null_ )); DATA(insert OID = 2163 ( text_pattern_ge PGNSP PGUID 12 1 0 0 f f t f i 2 16 "25 25" _null_ _null_ _null_ text_pattern_ge _null_ _null_ _null_ )); Index: src/include/utils/array.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/utils/array.h,v retrieving revision 1.68 diff -c -r1.68 array.h *** src/include/utils/array.h 16 Jul 2008 00:48:54 -0000 1.68 --- src/include/utils/array.h 16 Oct 2008 02:22:13 -0000 *************** *** 204,209 **** --- 204,211 ---- extern Datum generate_subscripts_nodir(PG_FUNCTION_ARGS); extern Datum array_fill(PG_FUNCTION_ARGS); extern Datum array_fill_with_lower_bounds(PG_FUNCTION_ARGS); + extern Datum array_accum_trans(PG_FUNCTION_ARGS); + extern Datum array_accum_final(PG_FUNCTION_ARGS); extern Datum array_ref(ArrayType *array, int nSubscripts, int *indx, int arraytyplen, int elmlen, bool elmbyval, char elmalign,
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers