]> 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 468e444e139c4e5839e2008ea4a83d9de183f1c2..831466dec914946bdd95c73f25418784dbdba427 100644 (file)
@@ -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);
+}