]> granicus.if.org Git - postgresql/blobdiff - src/backend/utils/adt/array_userfuncs.c
pgindent run for 9.4
[postgresql] / src / backend / utils / adt / array_userfuncs.c
index 6f18c6640599c20e1d78414915d60590e5b3b887..831466dec914946bdd95c73f25418784dbdba427 100644 (file)
@@ -3,16 +3,15 @@
  * 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"
@@ -376,7 +375,7 @@ array_cat(PG_FUNCTION_ARGS)
                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;
@@ -408,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;
@@ -430,6 +431,7 @@ create_singleton_array(FunctionCallInfo fcinfo,
                                                ndims, MAXDIM)));
 
        dvalues[0] = element;
+       nulls[0] = isNull;
 
        for (i = 0; i < ndims; i++)
        {
@@ -463,7 +465,7 @@ 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);
 }
 
@@ -474,7 +476,8 @@ create_singleton_array(FunctionCallInfo fcinfo,
 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;
 
@@ -483,8 +486,11 @@ array_agg_transfn(PG_FUNCTION_ARGS)
                                (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);
@@ -492,17 +498,12 @@ array_agg_transfn(PG_FUNCTION_ARGS)
                                                         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);
 }
@@ -510,14 +511,36 @@ array_agg_transfn(PG_FUNCTION_ARGS)
 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);
 }