*** ./contrib/intagg/int_aggregate.c.orig 2006-07-11 21:04:12.000000000 +0400 --- ./contrib/intagg/int_aggregate.c 2008-03-13 20:42:00.000000000 +0300 *************** *** 62,68 **** #define START_NUM 8 /* initial size of arrays */ #define PGARRAY_SIZE(n) (sizeof(PGARRAY) + (((n)-1)*sizeof(int4))) ! static PGARRAY *GetPGArray(PGARRAY * p, AggState *aggstate, bool fAdd); static PGARRAY *ShrinkPGArray(PGARRAY * p); Datum int_agg_state(PG_FUNCTION_ARGS); --- 62,68 ---- #define START_NUM 8 /* initial size of arrays */ #define PGARRAY_SIZE(n) (sizeof(PGARRAY) + (((n)-1)*sizeof(int4))) ! static PGARRAY *GetPGArray(PGARRAY * p, AggState *aggstate, int nItemsToAdd); static PGARRAY *ShrinkPGArray(PGARRAY * p); Datum int_agg_state(PG_FUNCTION_ARGS); *************** *** 73,78 **** --- 73,82 ---- PG_FUNCTION_INFO_V1(int_agg_final_array); PG_FUNCTION_INFO_V1(int_enum); + /* Additional things. */ + Datum int_agg_append_state(PG_FUNCTION_ARGS); + PG_FUNCTION_INFO_V1(int_agg_append_state); + /* * Manage the allocation state of the array * *************** *** 80,91 **** * ie the Agg node's aggcontext. */ static PGARRAY * ! GetPGArray(PGARRAY * p, AggState *aggstate, bool fAdd) { if (!p) { /* New array */ ! int cb = PGARRAY_SIZE(START_NUM); p = (PGARRAY *) MemoryContextAlloc(aggstate->aggcontext, cb); p->a.size = cb; --- 84,96 ---- * ie the Agg node's aggcontext. */ static PGARRAY * ! GetPGArray(PGARRAY * p, AggState *aggstate, int nItemsToAdd) { if (!p) { /* New array */ ! int newSize = (nItemsToAdd > START_NUM? nItemsToAdd : START_NUM) * 2; ! int cb = PGARRAY_SIZE(newSize); p = (PGARRAY *) MemoryContextAlloc(aggstate->aggcontext, cb); p->a.size = cb; *************** *** 93,107 **** p->a.dataoffset = 0; /* we don't support nulls, for now */ p->a.elemtype = INT4OID; p->items = 0; ! p->lower = START_NUM; } ! else if (fAdd) { /* Ensure array has space for another item */ ! if (p->items >= p->lower) { PGARRAY *pn; ! int n = p->lower * 2; int cbNew = PGARRAY_SIZE(n); pn = (PGARRAY *) MemoryContextAlloc(aggstate->aggcontext, cbNew); --- 98,112 ---- p->a.dataoffset = 0; /* we don't support nulls, for now */ p->a.elemtype = INT4OID; p->items = 0; ! p->lower = newSize; } ! else if (nItemsToAdd > 0) { /* Ensure array has space for another item */ ! if (p->items + nItemsToAdd - 1 >= p->lower) { PGARRAY *pn; ! int n = (p->lower + nItemsToAdd - 1) * 2; int cbNew = PGARRAY_SIZE(n); pn = (PGARRAY *) MemoryContextAlloc(aggstate->aggcontext, cbNew); *************** *** 158,164 **** state = NULL; /* first time through */ else state = (PGARRAY *) PG_GETARG_POINTER(0); ! p = GetPGArray(state, (AggState *) fcinfo->context, true); if (!PG_ARGISNULL(1)) { --- 163,169 ---- state = NULL; /* first time through */ else state = (PGARRAY *) PG_GETARG_POINTER(0); ! p = GetPGArray(state, (AggState *) fcinfo->context, 1); if (!PG_ARGISNULL(1)) { *************** *** 174,179 **** --- 179,185 ---- PG_RETURN_POINTER(p); } + /* * This is the final function used for the integer aggregator. It returns all * the integers collected as a one dimensional integer array *************** *** 196,202 **** state = NULL; /* zero items in aggregation */ else state = (PGARRAY *) PG_GETARG_POINTER(0); ! p = GetPGArray(state, (AggState *) fcinfo->context, false); pnew = ShrinkPGArray(p); PG_RETURN_POINTER(pnew); --- 202,208 ---- state = NULL; /* zero items in aggregation */ else state = (PGARRAY *) PG_GETARG_POINTER(0); ! p = GetPGArray(state, (AggState *) fcinfo->context, 0); pnew = ShrinkPGArray(p); PG_RETURN_POINTER(pnew); *************** *** 278,280 **** --- 284,338 ---- } PG_RETURN_NULL(); } + + + /** + * Additional things. + */ + + /* Called for each iteration during an aggregate function */ + Datum + int_agg_append_state(PG_FUNCTION_ARGS) + { + PGARRAY *state; + PGARRAY *p; + + /* + * As of PG 8.1 we can actually verify that we are being used as an + * aggregate function, and so it is safe to scribble on our left input. + */ + if (!(fcinfo->context && IsA(fcinfo->context, AggState))) + elog(ERROR, "int_agg_append_state may only be used as an aggregate"); + + if (PG_ARGISNULL(0)) + state = NULL; /* first time through */ + else + state = (PGARRAY *) PG_GETARG_POINTER(0); + + p = NULL; + if (!PG_ARGISNULL(1)) + { + ArrayType *a = (ArrayType *)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(1))); + if (a != NULL) { + int nItems = ArrayGetNItems(ARR_NDIM(a), ARR_DIMS(a)); + if (nItems > 0) { + p = GetPGArray(state, (AggState *) fcinfo->context, nItems); + if (!p) /* internal error */ + elog(ERROR, "no aggregate storage"); + else if (p->items + nItems - 1 >= p->lower) /* internal error */ + elog(ERROR, "aggregate storage too small"); + else { + int4 *data = (int4 *)ARR_DATA_PTR(a); + memcpy(&(p->array[p->items]), data, nItems * sizeof(int4)); + p->items += nItems; + } + } + } + PG_FREE_IF_COPY(a, 1); + + } + if (p == NULL) { + p = GetPGArray(state, (AggState *) fcinfo->context, 0); + } + PG_RETURN_POINTER(p); + } *** ./contrib/intagg/int_aggregate.sql.in.orig 2005-03-12 23:25:06.000000000 +0300 --- ./contrib/intagg/int_aggregate.sql.in 2008-03-13 20:45:00.000000000 +0300 *************** *** 31,33 **** --- 31,56 ---- RETURNS setof integer AS 'MODULE_PATHNAME','int_enum' LANGUAGE C IMMUTABLE STRICT; + + + + -- + -- Additional things. + -- + + + -- Internal function for appending arrays + -- Is called for each item in an glue aggregation + CREATE OR REPLACE FUNCTION int_agg_append_state (int4[], int4[]) + RETURNS int4[] + AS 'MODULE_PATHNAME','int_agg_append_state' + LANGUAGE C; + + -- The aggregate function itself for array glueing + -- uses the above functions to create an array of integers from an aggregation. + CREATE AGGREGATE int_array_append_aggregate ( + BASETYPE = int4[], + SFUNC = int_agg_append_state, + STYPE = int4[], + FINALFUNC = int_agg_final_array + ); *** ./contrib/intagg/uninstall_int_aggregate.sql.orig 2006-02-27 15:54:39.000000000 +0300 --- ./contrib/intagg/uninstall_int_aggregate.sql 2008-03-13 20:45:00.000000000 +0300 *************** *** 1,5 **** --- 1,16 ---- SET search_path = public; + -- + -- Additional things. + -- + + DROP AGGREGATE int_array_append_aggregate (int4[]); + + DROP FUNCTION int_agg_append_state (int4[], int4[]); + + + -- Default things. + DROP FUNCTION int_array_enum(int4[]); DROP AGGREGATE int_array_aggregate (int4); *************** *** 7,9 **** --- 18,22 ---- DROP FUNCTION int_agg_final_array (int4[]); DROP FUNCTION int_agg_state (int4[], int4); + +