* 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"
/*-----------------------------------------------------------------------------
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);
}
{
/*
* 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));
/* 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++)
{
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;
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;
ndims, MAXDIM)));
dvalues[0] = element;
+ nulls[0] = isNull;
for (i = 0; i < ndims; i++)
{
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);
+}