X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=src%2Fbackend%2Futils%2Fadt%2Farray_userfuncs.c;h=831466dec914946bdd95c73f25418784dbdba427;hb=0a7832005792fa6dad171f9cadb8d587fe0dd800;hp=468e444e139c4e5839e2008ea4a83d9de183f1c2;hpb=cecb6075594a407b7adcd9c9a0c243ca4b43c9a3;p=postgresql diff --git a/src/backend/utils/adt/array_userfuncs.c b/src/backend/utils/adt/array_userfuncs.c index 468e444e13..831466dec9 100644 --- a/src/backend/utils/adt/array_userfuncs.c +++ b/src/backend/utils/adt/array_userfuncs.c @@ -3,21 +3,18 @@ * array_userfuncs.c * Misc user-visible array support functions * - * Copyright (c) 2003-2005, PostgreSQL Global Development Group + * Copyright (c) 2003-2014, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/array_userfuncs.c,v 1.17 2005/11/17 22:14:52 tgl Exp $ + * src/backend/utils/adt/array_userfuncs.c * *------------------------------------------------------------------------- */ #include "postgres.h" -#include "catalog/pg_proc.h" -#include "catalog/pg_type.h" #include "utils/array.h" #include "utils/builtins.h" #include "utils/lsyscache.h" -#include "utils/syscache.h" /*----------------------------------------------------------------------------- @@ -152,6 +149,13 @@ array_push(PG_FUNCTION_ARGS) result = array_set(v, 1, &indx, newelem, isNull, -1, typlen, typbyval, typalign); + /* + * Readjust result's LB to match the input's. This does nothing in the + * append case, but it's the simplest way to implement the prepend case. + */ + if (ARR_NDIM(v) == 1) + ARR_LBOUND(result)[0] = ARR_LBOUND(v)[0]; + PG_RETURN_ARRAYTYPE_P(result); } @@ -305,7 +309,7 @@ array_cat(PG_FUNCTION_ARGS) { /* * resulting array has the second argument as the outer array, with - * the first argument appended to the front of the outer dimension + * the first argument inserted at the front of the outer dimension */ ndims = ndims2; dims = (int *) palloc(ndims * sizeof(int)); @@ -316,9 +320,6 @@ array_cat(PG_FUNCTION_ARGS) /* increment number of elements in outer array */ dims[0] += 1; - /* decrement outer array lower bound */ - lbs[0] -= 1; - /* make sure the added element matches our existing elements */ for (i = 0; i < ndims1; i++) { @@ -374,8 +375,8 @@ array_cat(PG_FUNCTION_ARGS) dataoffset = 0; /* marker for no null bitmap */ nbytes = ndatabytes + ARR_OVERHEAD_NONULLS(ndims); } - result = (ArrayType *) palloc(nbytes); - result->size = nbytes; + result = (ArrayType *) palloc0(nbytes); + SET_VARSIZE(result, nbytes); result->ndim = ndims; result->dataoffset = dataoffset; result->elemtype = element_type; @@ -406,9 +407,11 @@ ArrayType * create_singleton_array(FunctionCallInfo fcinfo, Oid element_type, Datum element, + bool isNull, int ndims) { Datum dvalues[1]; + bool nulls[1]; int16 typlen; bool typbyval; char typalign; @@ -428,6 +431,7 @@ create_singleton_array(FunctionCallInfo fcinfo, ndims, MAXDIM))); dvalues[0] = element; + nulls[0] = isNull; for (i = 0; i < ndims; i++) { @@ -461,6 +465,82 @@ create_singleton_array(FunctionCallInfo fcinfo, typbyval = my_extra->typbyval; typalign = my_extra->typalign; - return construct_md_array(dvalues, NULL, ndims, dims, lbs, element_type, + return construct_md_array(dvalues, nulls, ndims, dims, lbs, element_type, typlen, typbyval, typalign); } + + +/* + * ARRAY_AGG aggregate function + */ +Datum +array_agg_transfn(PG_FUNCTION_ARGS) +{ + Oid arg1_typeid = get_fn_expr_argtype(fcinfo->flinfo, 1); + MemoryContext aggcontext; + ArrayBuildState *state; + Datum elem; + + if (arg1_typeid == InvalidOid) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("could not determine input data type"))); + + if (!AggCheckCallContext(fcinfo, &aggcontext)) + { + /* cannot be called directly because of internal-type argument */ + elog(ERROR, "array_agg_transfn called in non-aggregate context"); + } + + state = PG_ARGISNULL(0) ? NULL : (ArrayBuildState *) PG_GETARG_POINTER(0); + elem = PG_ARGISNULL(1) ? (Datum) 0 : PG_GETARG_DATUM(1); + state = accumArrayResult(state, + elem, + 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 ArrayBuildState pointer through nodeAgg.c's machinations. + */ + PG_RETURN_POINTER(state); +} + +Datum +array_agg_finalfn(PG_FUNCTION_ARGS) +{ + Datum result; + ArrayBuildState *state; + 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); + + dims[0] = state->nelems; + lbs[0] = 1; + + /* + * Make the result. We cannot release the ArrayBuildState 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 = makeMdArrayResult(state, 1, dims, lbs, + CurrentMemoryContext, + false); + + PG_RETURN_DATUM(result); +}