* array_userfuncs.c
* Misc user-visible array support functions
*
- * Copyright (c) 2003-2008, PostgreSQL Global Development Group
+ * Copyright (c) 2003-2014, PostgreSQL Global Development Group
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/array_userfuncs.c,v 1.25 2008/11/14 00:12:08 tgl Exp $
+ * src/backend/utils/adt/array_userfuncs.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
-#include "nodes/execnodes.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
dataoffset = 0; /* marker for no null bitmap */
nbytes = ndatabytes + ARR_OVERHEAD_NONULLS(ndims);
}
- result = (ArrayType *) palloc(nbytes);
+ result = (ArrayType *) palloc0(nbytes);
SET_VARSIZE(result, nbytes);
result->ndim = ndims;
result->dataoffset = dataoffset;
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);
}
Datum
array_agg_transfn(PG_FUNCTION_ARGS)
{
- Oid arg1_typeid = get_fn_expr_argtype(fcinfo->flinfo, 1);
+ Oid arg1_typeid = get_fn_expr_argtype(fcinfo->flinfo, 1);
+ MemoryContext aggcontext;
ArrayBuildState *state;
Datum elem;
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("could not determine input data type")));
- /* cannot be called directly because of internal-type argument */
- Assert(fcinfo->context && IsA(fcinfo->context, AggState));
+ 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);
elem,
PG_ARGISNULL(1),
arg1_typeid,
- ((AggState *) fcinfo->context)->aggcontext);
+ aggcontext);
/*
- * We cheat quite a lot here by assuming that a pointer datum will be
- * preserved intact when nodeAgg.c thinks it is a value of type "internal".
- * This will in fact work because internal is stated to be pass-by-value
- * in pg_type.h, and nodeAgg will never do anything with a pass-by-value
- * transvalue except pass it around in Datum form. But it's mighty
- * shaky seeing that internal is also stated to be 4 bytes wide in
- * pg_type.h. If nodeAgg did put the value into a tuple this would
- * crash and burn on 64-bit machines.
+ * 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];
- /* cannot be called directly because of internal-type argument */
- Assert(fcinfo->context && IsA(fcinfo->context, AggState));
-
+ /*
+ * 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 */
+ 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);
- PG_RETURN_ARRAYTYPE_P(makeArrayResult(state, CurrentMemoryContext));
+
+ 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);
}