diff options
Diffstat (limited to 'src/backend/utils/adt/array_userfuncs.c')
-rw-r--r-- | src/backend/utils/adt/array_userfuncs.c | 88 |
1 files changed, 78 insertions, 10 deletions
diff --git a/src/backend/utils/adt/array_userfuncs.c b/src/backend/utils/adt/array_userfuncs.c index 831466dec91..50ea4d226b7 100644 --- a/src/backend/utils/adt/array_userfuncs.c +++ b/src/backend/utils/adt/array_userfuncs.c @@ -471,7 +471,7 @@ create_singleton_array(FunctionCallInfo fcinfo, /* - * ARRAY_AGG aggregate function + * ARRAY_AGG(anynonarray) aggregate function */ Datum array_agg_transfn(PG_FUNCTION_ARGS) @@ -486,6 +486,12 @@ array_agg_transfn(PG_FUNCTION_ARGS) (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("could not determine input data type"))); + /* + * Note: we do not need a run-time check about whether arg1_typeid is a + * valid array element type, because the parser would have verified that + * while resolving the input/result types of this polymorphic aggregate. + */ + if (!AggCheckCallContext(fcinfo, &aggcontext)) { /* cannot be called directly because of internal-type argument */ @@ -516,18 +522,13 @@ array_agg_finalfn(PG_FUNCTION_ARGS) int dims[1]; int lbs[1]; - /* - * Test for null before Asserting we are in right context. This is to - * avoid possible Assert failure in 8.4beta installations, where it is - * possible for users to create NULL constants of type internal. - */ - if (PG_ARGISNULL(0)) - PG_RETURN_NULL(); /* returns null iff no input values */ - /* cannot be called directly because of internal-type argument */ Assert(AggCheckCallContext(fcinfo, NULL)); - state = (ArrayBuildState *) PG_GETARG_POINTER(0); + state = PG_ARGISNULL(0) ? NULL : (ArrayBuildState *) PG_GETARG_POINTER(0); + + if (state == NULL) + PG_RETURN_NULL(); /* returns null iff no input values */ dims[0] = state->nelems; lbs[0] = 1; @@ -544,3 +545,70 @@ array_agg_finalfn(PG_FUNCTION_ARGS) PG_RETURN_DATUM(result); } + +/* + * ARRAY_AGG(anyarray) aggregate function + */ +Datum +array_agg_array_transfn(PG_FUNCTION_ARGS) +{ + Oid arg1_typeid = get_fn_expr_argtype(fcinfo->flinfo, 1); + MemoryContext aggcontext; + ArrayBuildStateArr *state; + + if (arg1_typeid == InvalidOid) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("could not determine input data type"))); + + /* + * Note: we do not need a run-time check about whether arg1_typeid is a + * valid array type, because the parser would have verified that while + * resolving the input/result types of this polymorphic aggregate. + */ + + if (!AggCheckCallContext(fcinfo, &aggcontext)) + { + /* cannot be called directly because of internal-type argument */ + elog(ERROR, "array_agg_array_transfn called in non-aggregate context"); + } + + state = PG_ARGISNULL(0) ? NULL : (ArrayBuildStateArr *) PG_GETARG_POINTER(0); + state = accumArrayResultArr(state, + PG_GETARG_DATUM(1), + PG_ARGISNULL(1), + arg1_typeid, + aggcontext); + + /* + * The transition type for array_agg() is declared to be "internal", which + * is a pass-by-value type the same size as a pointer. So we can safely + * pass the ArrayBuildStateArr pointer through nodeAgg.c's machinations. + */ + PG_RETURN_POINTER(state); +} + +Datum +array_agg_array_finalfn(PG_FUNCTION_ARGS) +{ + Datum result; + ArrayBuildStateArr *state; + + /* cannot be called directly because of internal-type argument */ + Assert(AggCheckCallContext(fcinfo, NULL)); + + state = PG_ARGISNULL(0) ? NULL : (ArrayBuildStateArr *) PG_GETARG_POINTER(0); + + if (state == NULL) + PG_RETURN_NULL(); /* returns null iff no input values */ + + /* + * Make the result. We cannot release the ArrayBuildStateArr because + * sometimes aggregate final functions are re-executed. Rather, it is + * nodeAgg.c's responsibility to reset the aggcontext when it's safe to do + * so. + */ + result = makeArrayResultArr(state, CurrentMemoryContext, false); + + PG_RETURN_DATUM(result); +} |