LCOV - code coverage report
Current view: top level - src/backend/utils/adt - arrayfuncs.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 88.6 % 3158 2797
Test Date: 2026-01-26 10:56:24 Functions: 96.7 % 90 87
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 64.9 % 2201 1429

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * arrayfuncs.c
       4                 :             :  *        Support functions for arrays.
       5                 :             :  *
       6                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
       8                 :             :  *
       9                 :             :  *
      10                 :             :  * IDENTIFICATION
      11                 :             :  *        src/backend/utils/adt/arrayfuncs.c
      12                 :             :  *
      13                 :             :  *-------------------------------------------------------------------------
      14                 :             :  */
      15                 :             : #include "postgres.h"
      16                 :             : 
      17                 :             : #include <ctype.h>
      18                 :             : #include <math.h>
      19                 :             : 
      20                 :             : #include "access/transam.h"
      21                 :             : #include "catalog/pg_type.h"
      22                 :             : #include "common/int.h"
      23                 :             : #include "funcapi.h"
      24                 :             : #include "libpq/pqformat.h"
      25                 :             : #include "nodes/nodeFuncs.h"
      26                 :             : #include "nodes/supportnodes.h"
      27                 :             : #include "optimizer/optimizer.h"
      28                 :             : #include "parser/scansup.h"
      29                 :             : #include "port/pg_bitutils.h"
      30                 :             : #include "utils/array.h"
      31                 :             : #include "utils/arrayaccess.h"
      32                 :             : #include "utils/builtins.h"
      33                 :             : #include "utils/datum.h"
      34                 :             : #include "utils/fmgroids.h"
      35                 :             : #include "utils/lsyscache.h"
      36                 :             : #include "utils/memutils.h"
      37                 :             : #include "utils/selfuncs.h"
      38                 :             : #include "utils/typcache.h"
      39                 :             : 
      40                 :             : 
      41                 :             : /*
      42                 :             :  * GUC parameter
      43                 :             :  */
      44                 :             : bool            Array_nulls = true;
      45                 :             : 
      46                 :             : /*
      47                 :             :  * Local definitions
      48                 :             :  */
      49                 :             : #define ASSGN    "="
      50                 :             : 
      51                 :             : #define AARR_FREE_IF_COPY(array,n) \
      52                 :             :         do { \
      53                 :             :                 if (!VARATT_IS_EXPANDED_HEADER(array)) \
      54                 :             :                         PG_FREE_IF_COPY(array, n); \
      55                 :             :         } while (0)
      56                 :             : 
      57                 :             : /* ReadArrayToken return type */
      58                 :             : typedef enum
      59                 :             : {
      60                 :             :         ATOK_LEVEL_START,
      61                 :             :         ATOK_LEVEL_END,
      62                 :             :         ATOK_DELIM,
      63                 :             :         ATOK_ELEM,
      64                 :             :         ATOK_ELEM_NULL,
      65                 :             :         ATOK_ERROR,
      66                 :             : } ArrayToken;
      67                 :             : 
      68                 :             : /* Working state for array_iterate() */
      69                 :             : typedef struct ArrayIteratorData
      70                 :             : {
      71                 :             :         /* basic info about the array, set up during array_create_iterator() */
      72                 :             :         ArrayType  *arr;                        /* array we're iterating through */
      73                 :             :         bits8      *nullbitmap;         /* its null bitmap, if any */
      74                 :             :         int                     nitems;                 /* total number of elements in array */
      75                 :             :         int16           typlen;                 /* element type's length */
      76                 :             :         bool            typbyval;               /* element type's byval property */
      77                 :             :         char            typalign;               /* element type's align property */
      78                 :             : 
      79                 :             :         /* information about the requested slice size */
      80                 :             :         int                     slice_ndim;             /* slice dimension, or 0 if not slicing */
      81                 :             :         int                     slice_len;              /* number of elements per slice */
      82                 :             :         int                *slice_dims;         /* slice dims array */
      83                 :             :         int                *slice_lbound;       /* slice lbound array */
      84                 :             :         Datum      *slice_values;       /* workspace of length slice_len */
      85                 :             :         bool       *slice_nulls;        /* workspace of length slice_len */
      86                 :             : 
      87                 :             :         /* current position information, updated on each iteration */
      88                 :             :         char       *data_ptr;           /* our current position in the array */
      89                 :             :         int                     current_item;   /* the item # we're at in the array */
      90                 :             : } ArrayIteratorData;
      91                 :             : 
      92                 :             : static bool ReadArrayDimensions(char **srcptr, int *ndim_p,
      93                 :             :                                                                 int *dim, int *lBound,
      94                 :             :                                                                 const char *origStr, Node *escontext);
      95                 :             : static bool ReadDimensionInt(char **srcptr, int *result,
      96                 :             :                                                          const char *origStr, Node *escontext);
      97                 :             : static bool ReadArrayStr(char **srcptr,
      98                 :             :                                                  FmgrInfo *inputproc, Oid typioparam, int32 typmod,
      99                 :             :                                                  char typdelim,
     100                 :             :                                                  int typlen, bool typbyval, char typalign,
     101                 :             :                                                  int *ndim_p, int *dim,
     102                 :             :                                                  int *nitems_p,
     103                 :             :                                                  Datum **values_p, bool **nulls_p,
     104                 :             :                                                  const char *origStr, Node *escontext);
     105                 :             : static ArrayToken ReadArrayToken(char **srcptr, StringInfo elembuf, char typdelim,
     106                 :             :                                                                  const char *origStr, Node *escontext);
     107                 :             : static void ReadArrayBinary(StringInfo buf, int nitems,
     108                 :             :                                                         FmgrInfo *receiveproc, Oid typioparam, int32 typmod,
     109                 :             :                                                         int typlen, bool typbyval, char typalign,
     110                 :             :                                                         Datum *values, bool *nulls,
     111                 :             :                                                         bool *hasnulls, int32 *nbytes);
     112                 :             : static Datum array_get_element_expanded(Datum arraydatum,
     113                 :             :                                                                                 int nSubscripts, int *indx,
     114                 :             :                                                                                 int arraytyplen,
     115                 :             :                                                                                 int elmlen, bool elmbyval, char elmalign,
     116                 :             :                                                                                 bool *isNull);
     117                 :             : static Datum array_set_element_expanded(Datum arraydatum,
     118                 :             :                                                                                 int nSubscripts, int *indx,
     119                 :             :                                                                                 Datum dataValue, bool isNull,
     120                 :             :                                                                                 int arraytyplen,
     121                 :             :                                                                                 int elmlen, bool elmbyval, char elmalign);
     122                 :             : static bool array_get_isnull(const bits8 *nullbitmap, int offset);
     123                 :             : static void array_set_isnull(bits8 *nullbitmap, int offset, bool isNull);
     124                 :             : static Datum ArrayCast(char *value, bool byval, int len);
     125                 :             : static int      ArrayCastAndSet(Datum src,
     126                 :             :                                                         int typlen, bool typbyval, char typalign,
     127                 :             :                                                         char *dest);
     128                 :             : static char *array_seek(char *ptr, int offset, bits8 *nullbitmap, int nitems,
     129                 :             :                                                 int typlen, bool typbyval, char typalign);
     130                 :             : static int      array_nelems_size(char *ptr, int offset, bits8 *nullbitmap,
     131                 :             :                                                           int nitems, int typlen, bool typbyval, char typalign);
     132                 :             : static int      array_copy(char *destptr, int nitems,
     133                 :             :                                            char *srcptr, int offset, bits8 *nullbitmap,
     134                 :             :                                            int typlen, bool typbyval, char typalign);
     135                 :             : static int      array_slice_size(char *arraydataptr, bits8 *arraynullsptr,
     136                 :             :                                                          int ndim, int *dim, int *lb,
     137                 :             :                                                          int *st, int *endp,
     138                 :             :                                                          int typlen, bool typbyval, char typalign);
     139                 :             : static void array_extract_slice(ArrayType *newarray,
     140                 :             :                                                                 int ndim, int *dim, int *lb,
     141                 :             :                                                                 char *arraydataptr, bits8 *arraynullsptr,
     142                 :             :                                                                 int *st, int *endp,
     143                 :             :                                                                 int typlen, bool typbyval, char typalign);
     144                 :             : static void array_insert_slice(ArrayType *destArray, ArrayType *origArray,
     145                 :             :                                                            ArrayType *srcArray,
     146                 :             :                                                            int ndim, int *dim, int *lb,
     147                 :             :                                                            int *st, int *endp,
     148                 :             :                                                            int typlen, bool typbyval, char typalign);
     149                 :             : static int      array_cmp(FunctionCallInfo fcinfo);
     150                 :             : static ArrayType *create_array_envelope(int ndims, int *dimv, int *lbsv, int nbytes,
     151                 :             :                                                                                 Oid elmtype, int dataoffset);
     152                 :             : static ArrayType *array_fill_internal(ArrayType *dims, ArrayType *lbs,
     153                 :             :                                                                           Datum value, bool isnull, Oid elmtype,
     154                 :             :                                                                           FunctionCallInfo fcinfo);
     155                 :             : static ArrayType *array_replace_internal(ArrayType *array,
     156                 :             :                                                                                  Datum search, bool search_isnull,
     157                 :             :                                                                                  Datum replace, bool replace_isnull,
     158                 :             :                                                                                  bool remove, Oid collation,
     159                 :             :                                                                                  FunctionCallInfo fcinfo);
     160                 :             : static int      width_bucket_array_float8(Datum operand, ArrayType *thresholds);
     161                 :             : static int      width_bucket_array_fixed(Datum operand,
     162                 :             :                                                                          ArrayType *thresholds,
     163                 :             :                                                                          Oid collation,
     164                 :             :                                                                          TypeCacheEntry *typentry);
     165                 :             : static int      width_bucket_array_variable(Datum operand,
     166                 :             :                                                                                 ArrayType *thresholds,
     167                 :             :                                                                                 Oid collation,
     168                 :             :                                                                                 TypeCacheEntry *typentry);
     169                 :             : 
     170                 :             : 
     171                 :             : /*
     172                 :             :  * array_in :
     173                 :             :  *                converts an array from the external format in "string" to
     174                 :             :  *                its internal format.
     175                 :             :  *
     176                 :             :  * return value :
     177                 :             :  *                the internal representation of the input array
     178                 :             :  */
     179                 :             : Datum
     180                 :        4558 : array_in(PG_FUNCTION_ARGS)
     181                 :             : {
     182                 :        4558 :         char       *string = PG_GETARG_CSTRING(0);      /* external form */
     183                 :        4558 :         Oid                     element_type = PG_GETARG_OID(1);        /* type of an array
     184                 :             :                                                                                                          * element */
     185                 :        4558 :         int32           typmod = PG_GETARG_INT32(2);    /* typmod for array elements */
     186                 :        4558 :         Node       *escontext = fcinfo->context;
     187                 :        4558 :         int                     typlen;
     188                 :        4558 :         bool            typbyval;
     189                 :        4558 :         char            typalign;
     190                 :        4558 :         char            typdelim;
     191                 :        4558 :         Oid                     typioparam;
     192                 :        4558 :         char       *p;
     193                 :        4558 :         int                     nitems;
     194                 :        4558 :         Datum      *values;
     195                 :        4558 :         bool       *nulls;
     196                 :        4558 :         bool            hasnulls;
     197                 :        4558 :         int32           nbytes;
     198                 :        4558 :         int32           dataoffset;
     199                 :        4558 :         ArrayType  *retval;
     200                 :        4558 :         int                     ndim,
     201                 :             :                                 dim[MAXDIM],
     202                 :             :                                 lBound[MAXDIM];
     203                 :        4558 :         ArrayMetaState *my_extra;
     204                 :             : 
     205                 :             :         /*
     206                 :             :          * We arrange to look up info about element type, including its input
     207                 :             :          * conversion proc, only once per series of calls, assuming the element
     208                 :             :          * type doesn't change underneath us.
     209                 :             :          */
     210                 :        4558 :         my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
     211         [ +  + ]:        4558 :         if (my_extra == NULL)
     212                 :             :         {
     213                 :        3129 :                 fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
     214                 :             :                                                                                                           sizeof(ArrayMetaState));
     215                 :        3129 :                 my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
     216                 :        3129 :                 my_extra->element_type = ~element_type;
     217                 :        3129 :         }
     218                 :             : 
     219         [ +  + ]:        4558 :         if (my_extra->element_type != element_type)
     220                 :             :         {
     221                 :             :                 /*
     222                 :             :                  * Get info about element type, including its input conversion proc
     223                 :             :                  */
     224                 :        6264 :                 get_type_io_data(element_type, IOFunc_input,
     225                 :        3132 :                                                  &my_extra->typlen, &my_extra->typbyval,
     226                 :        3132 :                                                  &my_extra->typalign, &my_extra->typdelim,
     227                 :        3132 :                                                  &my_extra->typioparam, &my_extra->typiofunc);
     228                 :        6264 :                 fmgr_info_cxt(my_extra->typiofunc, &my_extra->proc,
     229                 :        3132 :                                           fcinfo->flinfo->fn_mcxt);
     230                 :        3132 :                 my_extra->element_type = element_type;
     231                 :        3132 :         }
     232                 :        4558 :         typlen = my_extra->typlen;
     233                 :        4558 :         typbyval = my_extra->typbyval;
     234                 :        4558 :         typalign = my_extra->typalign;
     235                 :        4558 :         typdelim = my_extra->typdelim;
     236                 :        4558 :         typioparam = my_extra->typioparam;
     237                 :             : 
     238                 :             :         /*
     239                 :             :          * Initialize dim[] and lBound[] for ReadArrayStr, in case there is no
     240                 :             :          * explicit dimension info.  (If there is, ReadArrayDimensions will
     241                 :             :          * overwrite this.)
     242                 :             :          */
     243         [ +  + ]:       32098 :         for (int i = 0; i < MAXDIM; i++)
     244                 :             :         {
     245                 :       27540 :                 dim[i] = -1;                    /* indicates "not yet known" */
     246                 :       27540 :                 lBound[i] = 1;                  /* default lower bound */
     247                 :       27540 :         }
     248                 :             : 
     249                 :             :         /*
     250                 :             :          * Start processing the input string.
     251                 :             :          *
     252                 :             :          * If the input string starts with dimension info, read and use that.
     253                 :             :          * Otherwise, we'll determine the dimensions during ReadArrayStr.
     254                 :             :          */
     255                 :        4558 :         p = string;
     256         [ +  - ]:        4558 :         if (!ReadArrayDimensions(&p, &ndim, dim, lBound, string, escontext))
     257                 :           0 :                 return (Datum) 0;
     258                 :             : 
     259         [ +  + ]:        4558 :         if (ndim == 0)
     260                 :             :         {
     261                 :             :                 /* No array dimensions, so next character should be a left brace */
     262         [ +  + ]:        4535 :                 if (*p != '{')
     263         [ -  + ]:           1 :                         ereturn(escontext, (Datum) 0,
     264                 :             :                                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     265                 :             :                                          errmsg("malformed array literal: \"%s\"", string),
     266                 :             :                                          errdetail("Array value must start with \"{\" or dimension information.")));
     267                 :        4534 :         }
     268                 :             :         else
     269                 :             :         {
     270                 :             :                 /* If array dimensions are given, expect '=' operator */
     271         [ +  - ]:          23 :                 if (strncmp(p, ASSGN, strlen(ASSGN)) != 0)
     272         [ #  # ]:           0 :                         ereturn(escontext, (Datum) 0,
     273                 :             :                                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     274                 :             :                                          errmsg("malformed array literal: \"%s\"", string),
     275                 :             :                                          errdetail("Missing \"%s\" after array dimensions.",
     276                 :             :                                                            ASSGN)));
     277                 :          23 :                 p += strlen(ASSGN);
     278                 :             :                 /* Allow whitespace after it */
     279         [ -  + ]:          23 :                 while (scanner_isspace(*p))
     280                 :           0 :                         p++;
     281                 :             : 
     282         [ +  - ]:          23 :                 if (*p != '{')
     283         [ #  # ]:           0 :                         ereturn(escontext, (Datum) 0,
     284                 :             :                                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     285                 :             :                                          errmsg("malformed array literal: \"%s\"", string),
     286                 :             :                                          errdetail("Array contents must start with \"{\".")));
     287                 :             :         }
     288                 :             : 
     289                 :             :         /* Parse the value part, in the curly braces: { ... } */
     290         [ +  + ]:        4557 :         if (!ReadArrayStr(&p,
     291                 :        4557 :                                           &my_extra->proc, typioparam, typmod,
     292                 :        4557 :                                           typdelim,
     293                 :        4557 :                                           typlen, typbyval, typalign,
     294                 :             :                                           &ndim,
     295                 :        4557 :                                           dim,
     296                 :             :                                           &nitems,
     297                 :             :                                           &values, &nulls,
     298                 :        4557 :                                           string,
     299                 :        4557 :                                           escontext))
     300                 :           7 :                 return (Datum) 0;
     301                 :             : 
     302                 :             :         /* only whitespace is allowed after the closing brace */
     303         [ +  + ]:        4550 :         while (*p)
     304                 :             :         {
     305         [ +  - ]:           2 :                 if (!scanner_isspace(*p++))
     306         [ -  + ]:           2 :                         ereturn(escontext, (Datum) 0,
     307                 :             :                                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     308                 :             :                                          errmsg("malformed array literal: \"%s\"", string),
     309                 :             :                                          errdetail("Junk after closing right brace.")));
     310                 :             :         }
     311                 :             : 
     312                 :             :         /* Empty array? */
     313         [ +  + ]:        4548 :         if (nitems == 0)
     314                 :         423 :                 PG_RETURN_ARRAYTYPE_P(construct_empty_array(element_type));
     315                 :             : 
     316                 :             :         /*
     317                 :             :          * Check for nulls, compute total data space needed
     318                 :             :          */
     319                 :        4125 :         hasnulls = false;
     320                 :        4125 :         nbytes = 0;
     321   [ +  +  -  + ]:       36694 :         for (int i = 0; i < nitems; i++)
     322                 :             :         {
     323         [ +  + ]:       32569 :                 if (nulls[i])
     324                 :          67 :                         hasnulls = true;
     325                 :             :                 else
     326                 :             :                 {
     327                 :             :                         /* let's just make sure data is not toasted */
     328         [ +  + ]:       32502 :                         if (typlen == -1)
     329                 :        5861 :                                 values[i] = PointerGetDatum(PG_DETOAST_DATUM(values[i]));
     330   [ +  +  -  +  :       32502 :                         nbytes = att_addlength_datum(nbytes, typlen, values[i]);
                   #  # ]
     331   [ +  +  +  +  :       32502 :                         nbytes = att_align_nominal(nbytes, typalign);
             +  +  -  + ]
     332                 :             :                         /* check for overflow of total request */
     333         [ -  + ]:       32502 :                         if (!AllocSizeIsValid(nbytes))
     334         [ #  # ]:           0 :                                 ereturn(escontext, (Datum) 0,
     335                 :             :                                                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     336                 :             :                                                  errmsg("array size exceeds the maximum allowed (%zu)",
     337                 :             :                                                                 MaxAllocSize)));
     338                 :             :                 }
     339                 :       32569 :         }
     340         [ +  + ]:        4125 :         if (hasnulls)
     341                 :             :         {
     342                 :          60 :                 dataoffset = ARR_OVERHEAD_WITHNULLS(ndim, nitems);
     343                 :          60 :                 nbytes += dataoffset;
     344                 :          60 :         }
     345                 :             :         else
     346                 :             :         {
     347                 :        4065 :                 dataoffset = 0;                 /* marker for no null bitmap */
     348                 :        4065 :                 nbytes += ARR_OVERHEAD_NONULLS(ndim);
     349                 :             :         }
     350                 :             : 
     351                 :             :         /*
     352                 :             :          * Construct the final array datum
     353                 :             :          */
     354                 :        4125 :         retval = (ArrayType *) palloc0(nbytes);
     355                 :        4125 :         SET_VARSIZE(retval, nbytes);
     356                 :        4125 :         retval->ndim = ndim;
     357                 :        4125 :         retval->dataoffset = dataoffset;
     358                 :             : 
     359                 :             :         /*
     360                 :             :          * This comes from the array's pg_type.typelem (which points to the base
     361                 :             :          * data type's pg_type.oid) and stores system oids in user tables. This
     362                 :             :          * oid must be preserved by binary upgrades.
     363                 :             :          */
     364                 :        4125 :         retval->elemtype = element_type;
     365                 :        4125 :         memcpy(ARR_DIMS(retval), dim, ndim * sizeof(int));
     366                 :        4125 :         memcpy(ARR_LBOUND(retval), lBound, ndim * sizeof(int));
     367                 :             : 
     368                 :        8250 :         CopyArrayEls(retval,
     369                 :        4125 :                                  values, nulls, nitems,
     370                 :        4125 :                                  typlen, typbyval, typalign,
     371                 :             :                                  true);
     372                 :             : 
     373                 :        4125 :         pfree(values);
     374                 :        4125 :         pfree(nulls);
     375                 :             : 
     376                 :        4125 :         PG_RETURN_ARRAYTYPE_P(retval);
     377                 :        4558 : }
     378                 :             : 
     379                 :             : /*
     380                 :             :  * ReadArrayDimensions
     381                 :             :  *       parses the array dimensions part of the input and converts the values
     382                 :             :  *       to internal format.
     383                 :             :  *
     384                 :             :  * On entry, *srcptr points to the string to parse. It is advanced to point
     385                 :             :  * after whitespace (if any) and dimension info (if any).
     386                 :             :  *
     387                 :             :  * *ndim_p, dim[], and lBound[] are output variables. They are filled with the
     388                 :             :  * number of dimensions (<= MAXDIM), the lengths of each dimension, and the
     389                 :             :  * lower subscript bounds, respectively.  If no dimension info appears,
     390                 :             :  * *ndim_p will be set to zero, and dim[] and lBound[] are unchanged.
     391                 :             :  *
     392                 :             :  * 'origStr' is the original input string, used only in error messages.
     393                 :             :  * If *escontext points to an ErrorSaveContext, details of any error are
     394                 :             :  * reported there.
     395                 :             :  *
     396                 :             :  * Result:
     397                 :             :  *      true for success, false for failure (if escontext is provided).
     398                 :             :  *
     399                 :             :  * Note that dim[] and lBound[] are allocated by the caller, and must have
     400                 :             :  * MAXDIM elements.
     401                 :             :  */
     402                 :             : static bool
     403                 :        4590 : ReadArrayDimensions(char **srcptr, int *ndim_p, int *dim, int *lBound,
     404                 :             :                                         const char *origStr, Node *escontext)
     405                 :             : {
     406                 :        4590 :         char       *p = *srcptr;
     407                 :        4590 :         int                     ndim;
     408                 :             : 
     409                 :             :         /*
     410                 :             :          * Dimension info takes the form of one or more [n] or [m:n] items.  This
     411                 :             :          * loop iterates once per dimension item.
     412                 :             :          */
     413                 :        4590 :         ndim = 0;
     414                 :        4625 :         for (;;)
     415                 :             :         {
     416                 :        4625 :                 char       *q;
     417                 :        4625 :                 int                     ub;
     418                 :        4625 :                 int                     i;
     419                 :             : 
     420                 :             :                 /*
     421                 :             :                  * Note: we currently allow whitespace between, but not within,
     422                 :             :                  * dimension items.
     423                 :             :                  */
     424         [ +  + ]:        4627 :                 while (scanner_isspace(*p))
     425                 :           2 :                         p++;
     426         [ +  + ]:        4625 :                 if (*p != '[')
     427                 :        4583 :                         break;                          /* no more dimension items */
     428                 :          42 :                 p++;
     429         [ +  - ]:          42 :                 if (ndim >= MAXDIM)
     430         [ #  # ]:           0 :                         ereturn(escontext, false,
     431                 :             :                                         (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     432                 :             :                                          errmsg("number of array dimensions exceeds the maximum allowed (%d)",
     433                 :             :                                                         MAXDIM)));
     434                 :             : 
     435                 :          42 :                 q = p;
     436         [ +  - ]:          42 :                 if (!ReadDimensionInt(&p, &i, origStr, escontext))
     437                 :           0 :                         return false;
     438         [ +  + ]:          42 :                 if (p == q)                             /* no digits? */
     439         [ +  + ]:           2 :                         ereturn(escontext, false,
     440                 :             :                                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     441                 :             :                                          errmsg("malformed array literal: \"%s\"", origStr),
     442                 :             :                                          errdetail("\"[\" must introduce explicitly-specified array dimensions.")));
     443                 :             : 
     444         [ +  + ]:          40 :                 if (*p == ':')
     445                 :             :                 {
     446                 :             :                         /* [m:n] format */
     447                 :          35 :                         lBound[ndim] = i;
     448                 :          35 :                         p++;
     449                 :          35 :                         q = p;
     450         [ +  - ]:          35 :                         if (!ReadDimensionInt(&p, &ub, origStr, escontext))
     451                 :           0 :                                 return false;
     452         [ +  + ]:          35 :                         if (p == q)                     /* no digits? */
     453         [ +  + ]:           2 :                                 ereturn(escontext, false,
     454                 :             :                                                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     455                 :             :                                                  errmsg("malformed array literal: \"%s\"", origStr),
     456                 :             :                                                  errdetail("Missing array dimension value.")));
     457                 :          33 :                 }
     458                 :             :                 else
     459                 :             :                 {
     460                 :             :                         /* [n] format */
     461                 :           5 :                         lBound[ndim] = 1;
     462                 :           5 :                         ub = i;
     463                 :             :                 }
     464         [ +  - ]:          38 :                 if (*p != ']')
     465         [ #  # ]:           0 :                         ereturn(escontext, false,
     466                 :             :                                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     467                 :             :                                          errmsg("malformed array literal: \"%s\"", origStr),
     468                 :             :                                          errdetail("Missing \"%s\" after array dimensions.",
     469                 :             :                                                            "]")));
     470                 :          38 :                 p++;
     471                 :             : 
     472                 :             :                 /*
     473                 :             :                  * Note: we could accept ub = lb-1 to represent a zero-length
     474                 :             :                  * dimension.  However, that would result in an empty array, for which
     475                 :             :                  * we don't keep any dimension data, so that e.g. [1:0] and [101:100]
     476                 :             :                  * would be equivalent.  Given the lack of field demand, there seems
     477                 :             :                  * little point in allowing such cases.
     478                 :             :                  */
     479         [ +  + ]:          38 :                 if (ub < lBound[ndim])
     480         [ +  + ]:           4 :                         ereturn(escontext, false,
     481                 :             :                                         (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
     482                 :             :                                          errmsg("upper bound cannot be less than lower bound")));
     483                 :             : 
     484                 :             :                 /* Upper bound of INT_MAX must be disallowed, cf ArrayCheckBounds() */
     485         [ +  + ]:          34 :                 if (ub == INT_MAX)
     486         [ +  + ]:           2 :                         ereturn(escontext, false,
     487                 :             :                                         (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     488                 :             :                                          errmsg("array upper bound is too large: %d", ub)));
     489                 :             : 
     490                 :             :                 /* Compute "ub - lBound[ndim] + 1", detecting overflow */
     491   [ +  -  -  + ]:          32 :                 if (pg_sub_s32_overflow(ub, lBound[ndim], &ub) ||
     492                 :          32 :                         pg_add_s32_overflow(ub, 1, &ub))
     493         [ #  # ]:           0 :                         ereturn(escontext, false,
     494                 :             :                                         (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     495                 :             :                                          errmsg("array size exceeds the maximum allowed (%zu)",
     496                 :             :                                                         MaxArraySize)));
     497                 :             : 
     498                 :          32 :                 dim[ndim] = ub;
     499                 :          32 :                 ndim++;
     500      [ +  +  + ]:        4615 :         }
     501                 :             : 
     502                 :        4583 :         *srcptr = p;
     503                 :        4583 :         *ndim_p = ndim;
     504                 :        4583 :         return true;
     505                 :        4586 : }
     506                 :             : 
     507                 :             : /*
     508                 :             :  * ReadDimensionInt
     509                 :             :  *       parse an integer, for the array dimensions
     510                 :             :  *
     511                 :             :  * On entry, *srcptr points to the string to parse. It is advanced past the
     512                 :             :  * digits of the integer. If there are no digits, returns true and leaves
     513                 :             :  * *srcptr unchanged.
     514                 :             :  *
     515                 :             :  * Result:
     516                 :             :  *      true for success, false for failure (if escontext is provided).
     517                 :             :  *  On success, the parsed integer is returned in *result.
     518                 :             :  */
     519                 :             : static bool
     520                 :          75 : ReadDimensionInt(char **srcptr, int *result,
     521                 :             :                                  const char *origStr, Node *escontext)
     522                 :             : {
     523                 :          75 :         char       *p = *srcptr;
     524                 :          75 :         long            l;
     525                 :             : 
     526                 :             :         /* don't accept leading whitespace */
     527   [ +  +  +  +  :          75 :         if (!isdigit((unsigned char) *p) && *p != '-' && *p != '+')
                   -  + ]
     528                 :             :         {
     529                 :           2 :                 *result = 0;
     530                 :           2 :                 return true;
     531                 :             :         }
     532                 :             : 
     533                 :          73 :         errno = 0;
     534                 :          73 :         l = strtol(p, srcptr, 10);
     535                 :             : 
     536   [ +  +  +  +  :          73 :         if (errno == ERANGE || l > PG_INT32_MAX || l < PG_INT32_MIN)
                   +  + ]
     537         [ +  + ]:           4 :                 ereturn(escontext, false,
     538                 :             :                                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     539                 :             :                                  errmsg("array bound is out of integer range")));
     540                 :             : 
     541                 :          69 :         *result = (int) l;
     542                 :          69 :         return true;
     543                 :          71 : }
     544                 :             : 
     545                 :             : /*
     546                 :             :  * ReadArrayStr :
     547                 :             :  *       parses the array string pointed to by *srcptr and converts the values
     548                 :             :  *       to internal format.  Determines the array dimensions as it goes.
     549                 :             :  *
     550                 :             :  * On entry, *srcptr points to the string to parse (it must point to a '{').
     551                 :             :  * On successful return, it is advanced to point past the closing '}'.
     552                 :             :  *
     553                 :             :  * If dimensions were specified explicitly, they are passed in *ndim_p and
     554                 :             :  * dim[].  This function will check that the array values match the specified
     555                 :             :  * dimensions.  If dimensions were not given, caller must pass *ndim_p == 0
     556                 :             :  * and initialize all elements of dim[] to -1.  Then this function will
     557                 :             :  * deduce the dimensions from the structure of the input and store them in
     558                 :             :  * *ndim_p and the dim[] array.
     559                 :             :  *
     560                 :             :  * Element type information:
     561                 :             :  *      inputproc: type-specific input procedure for element datatype.
     562                 :             :  *      typioparam, typmod: auxiliary values to pass to inputproc.
     563                 :             :  *      typdelim: the value delimiter (type-specific).
     564                 :             :  *      typlen, typbyval, typalign: storage parameters of element datatype.
     565                 :             :  *
     566                 :             :  * Outputs:
     567                 :             :  *  *ndim_p, dim: dimensions deduced from the input structure.
     568                 :             :  *  *nitems_p: total number of elements.
     569                 :             :  *      *values_p[]: palloc'd array, filled with converted data values.
     570                 :             :  *      *nulls_p[]: palloc'd array, filled with is-null markers.
     571                 :             :  *
     572                 :             :  * 'origStr' is the original input string, used only in error messages.
     573                 :             :  * If *escontext points to an ErrorSaveContext, details of any error are
     574                 :             :  * reported there.
     575                 :             :  *
     576                 :             :  * Result:
     577                 :             :  *      true for success, false for failure (if escontext is provided).
     578                 :             :  */
     579                 :             : static bool
     580                 :        4581 : ReadArrayStr(char **srcptr,
     581                 :             :                          FmgrInfo *inputproc,
     582                 :             :                          Oid typioparam,
     583                 :             :                          int32 typmod,
     584                 :             :                          char typdelim,
     585                 :             :                          int typlen,
     586                 :             :                          bool typbyval,
     587                 :             :                          char typalign,
     588                 :             :                          int *ndim_p,
     589                 :             :                          int *dim,
     590                 :             :                          int *nitems_p,
     591                 :             :                          Datum **values_p,
     592                 :             :                          bool **nulls_p,
     593                 :             :                          const char *origStr,
     594                 :             :                          Node *escontext)
     595                 :             : {
     596                 :        4581 :         int                     ndim = *ndim_p;
     597                 :        4581 :         bool            dimensions_specified = (ndim != 0);
     598                 :        4581 :         int                     maxitems;
     599                 :        4581 :         Datum      *values;
     600                 :        4581 :         bool       *nulls;
     601                 :        4581 :         StringInfoData elembuf;
     602                 :        4581 :         int                     nest_level;
     603                 :        4581 :         int                     nitems;
     604                 :        4581 :         bool            ndim_frozen;
     605                 :        4581 :         bool            expect_delim;
     606                 :        4581 :         int                     nelems[MAXDIM];
     607                 :             : 
     608                 :             :         /* Allocate some starting output workspace; we'll enlarge as needed */
     609                 :        4581 :         maxitems = 16;
     610                 :        4581 :         values = palloc_array(Datum, maxitems);
     611                 :        4581 :         nulls = palloc_array(bool, maxitems);
     612                 :             : 
     613                 :             :         /* Allocate workspace to hold (string representation of) one element */
     614                 :        4581 :         initStringInfo(&elembuf);
     615                 :             : 
     616                 :             :         /* Loop below assumes first token is ATOK_LEVEL_START */
     617         [ +  - ]:        4581 :         Assert(**srcptr == '{');
     618                 :             : 
     619                 :             :         /* Parse tokens until we reach the matching right brace */
     620                 :        4581 :         nest_level = 0;
     621                 :        4581 :         nitems = 0;
     622                 :        4581 :         ndim_frozen = dimensions_specified;
     623                 :        4581 :         expect_delim = false;
     624                 :        4581 :         do
     625                 :             :         {
     626                 :       70669 :                 ArrayToken      tok;
     627                 :             : 
     628                 :       70669 :                 tok = ReadArrayToken(srcptr, &elembuf, typdelim, origStr, escontext);
     629                 :             : 
     630   [ +  +  -  +  :       70669 :                 switch (tok)
                   +  + ]
     631                 :             :                 {
     632                 :             :                         case ATOK_LEVEL_START:
     633                 :             :                                 /* Can't write left brace where delim is expected */
     634         [ +  + ]:        4819 :                                 if (expect_delim)
     635         [ +  + ]:           2 :                                         ereturn(escontext, false,
     636                 :             :                                                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     637                 :             :                                                          errmsg("malformed array literal: \"%s\"", origStr),
     638                 :             :                                                          errdetail("Unexpected \"%c\" character.", '{')));
     639                 :             : 
     640                 :             :                                 /* Initialize element counting in the new level */
     641         [ +  - ]:        4817 :                                 if (nest_level >= MAXDIM)
     642         [ #  # ]:           0 :                                         ereturn(escontext, false,
     643                 :             :                                                         (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     644                 :             :                                                          errmsg("number of array dimensions exceeds the maximum allowed (%d)",
     645                 :             :                                                                         MAXDIM)));
     646                 :             : 
     647                 :        4817 :                                 nelems[nest_level] = 0;
     648                 :        4817 :                                 nest_level++;
     649         [ +  + ]:        4817 :                                 if (nest_level > ndim)
     650                 :             :                                 {
     651                 :             :                                         /* Can't increase ndim once it's frozen */
     652         [ +  + ]:        4642 :                                         if (ndim_frozen)
     653                 :           2 :                                                 goto dimension_error;
     654                 :        4640 :                                         ndim = nest_level;
     655                 :        4640 :                                 }
     656                 :        4815 :                                 break;
     657                 :             : 
     658                 :             :                         case ATOK_LEVEL_END:
     659                 :             :                                 /* Can't get here with nest_level == 0 */
     660         [ -  + ]:        4786 :                                 Assert(nest_level > 0);
     661                 :             : 
     662                 :             :                                 /*
     663                 :             :                                  * We allow a right brace to terminate an empty sub-array,
     664                 :             :                                  * otherwise it must occur where we expect a delimiter.
     665                 :             :                                  */
     666   [ +  +  +  + ]:        4786 :                                 if (nelems[nest_level - 1] > 0 && !expect_delim)
     667         [ +  + ]:           8 :                                         ereturn(escontext, false,
     668                 :             :                                                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     669                 :             :                                                          errmsg("malformed array literal: \"%s\"", origStr),
     670                 :             :                                                          errdetail("Unexpected \"%c\" character.",
     671                 :             :                                                                            '}')));
     672                 :        4778 :                                 nest_level--;
     673                 :             :                                 /* Nested sub-arrays count as elements of outer level */
     674         [ +  + ]:        4778 :                                 if (nest_level > 0)
     675                 :         227 :                                         nelems[nest_level - 1]++;
     676                 :             : 
     677                 :             :                                 /*
     678                 :             :                                  * Note: if we had dimensionality info, then dim[nest_level]
     679                 :             :                                  * is initially non-negative, and we'll check each sub-array's
     680                 :             :                                  * length against that.
     681                 :             :                                  */
     682         [ +  + ]:        4778 :                                 if (dim[nest_level] < 0)
     683                 :             :                                 {
     684                 :             :                                         /* Save length of first sub-array of this level */
     685                 :        4605 :                                         dim[nest_level] = nelems[nest_level];
     686                 :        4605 :                                 }
     687         [ +  + ]:         173 :                                 else if (nelems[nest_level] != dim[nest_level])
     688                 :             :                                 {
     689                 :             :                                         /* Subsequent sub-arrays must have same length */
     690                 :           5 :                                         goto dimension_error;
     691                 :             :                                 }
     692                 :             : 
     693                 :             :                                 /*
     694                 :             :                                  * Must have a delim or another right brace following, unless
     695                 :             :                                  * we have reached nest_level 0, where this won't matter.
     696                 :             :                                  */
     697                 :        4773 :                                 expect_delim = true;
     698                 :        4773 :                                 break;
     699                 :             : 
     700                 :             :                         case ATOK_DELIM:
     701         [ +  + ]:       28465 :                                 if (!expect_delim)
     702         [ +  + ]:           2 :                                         ereturn(escontext, false,
     703                 :             :                                                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     704                 :             :                                                          errmsg("malformed array literal: \"%s\"", origStr),
     705                 :             :                                                          errdetail("Unexpected \"%c\" character.",
     706                 :             :                                                                            typdelim)));
     707                 :       28463 :                                 expect_delim = false;
     708                 :       28463 :                                 break;
     709                 :             : 
     710                 :             :                         case ATOK_ELEM:
     711                 :             :                         case ATOK_ELEM_NULL:
     712                 :             :                                 /* Can't get here with nest_level == 0 */
     713         [ +  - ]:       32598 :                                 Assert(nest_level > 0);
     714                 :             : 
     715                 :             :                                 /* Disallow consecutive ELEM tokens */
     716         [ +  + ]:       32598 :                                 if (expect_delim)
     717         [ +  + ]:           2 :                                         ereturn(escontext, false,
     718                 :             :                                                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     719                 :             :                                                          errmsg("malformed array literal: \"%s\"", origStr),
     720                 :             :                                                          errdetail("Unexpected array element.")));
     721                 :             : 
     722                 :             :                                 /* Enlarge the values/nulls arrays if needed */
     723         [ +  + ]:       32596 :                                 if (nitems >= maxitems)
     724                 :             :                                 {
     725         [ +  - ]:          44 :                                         if (maxitems >= MaxArraySize)
     726         [ #  # ]:           0 :                                                 ereturn(escontext, false,
     727                 :             :                                                                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     728                 :             :                                                                  errmsg("array size exceeds the maximum allowed (%zu)",
     729                 :             :                                                                                 MaxArraySize)));
     730         [ +  - ]:          44 :                                         maxitems = Min(maxitems * 2, MaxArraySize);
     731                 :          44 :                                         values = repalloc_array(values, Datum, maxitems);
     732                 :          44 :                                         nulls = repalloc_array(nulls, bool, maxitems);
     733                 :          44 :                                 }
     734                 :             : 
     735                 :             :                                 /* Read the element's value, or check that NULL is allowed */
     736         [ +  + ]:       65192 :                                 if (!InputFunctionCallSafe(inputproc,
     737         [ +  + ]:       32596 :                                                                                    (tok == ATOK_ELEM_NULL) ? NULL : elembuf.data,
     738                 :       32596 :                                                                                    typioparam, typmod,
     739                 :       32596 :                                                                                    escontext,
     740                 :       32596 :                                                                                    &values[nitems]))
     741                 :           6 :                                         return false;
     742                 :       32590 :                                 nulls[nitems] = (tok == ATOK_ELEM_NULL);
     743                 :       32590 :                                 nitems++;
     744                 :             : 
     745                 :             :                                 /*
     746                 :             :                                  * Once we have found an element, the number of dimensions can
     747                 :             :                                  * no longer increase, and subsequent elements must all be at
     748                 :             :                                  * the same nesting depth.
     749                 :             :                                  */
     750                 :       32590 :                                 ndim_frozen = true;
     751         [ +  + ]:       32590 :                                 if (nest_level != ndim)
     752                 :           2 :                                         goto dimension_error;
     753                 :             :                                 /* Count the new element */
     754                 :       32588 :                                 nelems[nest_level - 1]++;
     755                 :             : 
     756                 :             :                                 /* Must have a delim or a right brace following */
     757                 :       32588 :                                 expect_delim = true;
     758                 :       32588 :                                 break;
     759                 :             : 
     760                 :             :                         case ATOK_ERROR:
     761                 :           1 :                                 return false;
     762                 :             :                 }
     763   [ +  +  +  +  :       70655 :         } while (nest_level > 0);
                      + ]
     764                 :             : 
     765                 :             :         /* Clean up and return results */
     766                 :        4550 :         pfree(elembuf.data);
     767                 :             : 
     768                 :        4550 :         *ndim_p = ndim;
     769                 :        4550 :         *nitems_p = nitems;
     770                 :        4550 :         *values_p = values;
     771                 :        4550 :         *nulls_p = nulls;
     772                 :        4550 :         return true;
     773                 :             : 
     774                 :             : dimension_error:
     775         [ +  + ]:          18 :         if (dimensions_specified)
     776         [ +  + ]:           2 :                 ereturn(escontext, false,
     777                 :             :                                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     778                 :             :                                  errmsg("malformed array literal: \"%s\"", origStr),
     779                 :             :                                  errdetail("Specified array dimensions do not match array contents.")));
     780                 :             :         else
     781         [ +  + ]:          16 :                 ereturn(escontext, false,
     782                 :             :                                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     783                 :             :                                  errmsg("malformed array literal: \"%s\"", origStr),
     784                 :             :                                  errdetail("Multidimensional arrays must have sub-arrays with matching dimensions.")));
     785         [ -  + ]:        4551 : }
     786                 :             : 
     787                 :             : /*
     788                 :             :  * ReadArrayToken
     789                 :             :  *       read one token from an array value string
     790                 :             :  *
     791                 :             :  * Starts scanning from *srcptr.  On non-error return, *srcptr is
     792                 :             :  * advanced past the token.
     793                 :             :  *
     794                 :             :  * If the token is ATOK_ELEM, the de-escaped string is returned in elembuf.
     795                 :             :  */
     796                 :             : static ArrayToken
     797                 :       70671 : ReadArrayToken(char **srcptr, StringInfo elembuf, char typdelim,
     798                 :             :                            const char *origStr, Node *escontext)
     799                 :             : {
     800                 :       70671 :         char       *p = *srcptr;
     801                 :       70671 :         int                     dstlen;
     802                 :       70671 :         bool            has_escapes;
     803                 :             : 
     804                 :       70671 :         resetStringInfo(elembuf);
     805                 :             : 
     806                 :             :         /* Identify token type.  Loop advances over leading whitespace. */
     807                 :       70671 :         for (;;)
     808                 :             :         {
     809   [ +  -  +  +  :       72062 :                 switch (*p)
                      + ]
     810                 :             :                 {
     811                 :             :                         case '\0':
     812                 :           0 :                                 goto ending_error;
     813                 :             :                         case '{':
     814                 :        4818 :                                 *srcptr = p + 1;
     815                 :        4818 :                                 return ATOK_LEVEL_START;
     816                 :             :                         case '}':
     817                 :        4782 :                                 *srcptr = p + 1;
     818                 :        4782 :                                 return ATOK_LEVEL_END;
     819                 :             :                         case '"':
     820                 :        1359 :                                 p++;
     821                 :        1359 :                                 goto quoted_element;
     822                 :             :                         default:
     823         [ +  + ]:       61103 :                                 if (*p == typdelim)
     824                 :             :                                 {
     825                 :       28464 :                                         *srcptr = p + 1;
     826                 :       28464 :                                         return ATOK_DELIM;
     827                 :             :                                 }
     828         [ +  + ]:       32639 :                                 if (scanner_isspace(*p))
     829                 :             :                                 {
     830                 :        1391 :                                         p++;
     831                 :        1391 :                                         continue;
     832                 :             :                                 }
     833                 :       31248 :                                 goto unquoted_element;
     834                 :             :                 }
     835                 :             :         }
     836                 :             : 
     837                 :             : quoted_element:
     838                 :        9679 :         for (;;)
     839                 :             :         {
     840   [ +  +  -  + ]:        9679 :                 switch (*p)
     841                 :             :                 {
     842                 :             :                         case '\0':
     843                 :           0 :                                 goto ending_error;
     844                 :             :                         case '\\':
     845                 :             :                                 /* Skip backslash, copy next character as-is. */
     846                 :          27 :                                 p++;
     847         [ -  + ]:          27 :                                 if (*p == '\0')
     848                 :           0 :                                         goto ending_error;
     849                 :          27 :                                 appendStringInfoChar(elembuf, *p++);
     850                 :          27 :                                 break;
     851                 :             :                         case '"':
     852                 :             : 
     853                 :             :                                 /*
     854                 :             :                                  * If next non-whitespace isn't typdelim or a brace, complain
     855                 :             :                                  * about incorrect quoting.  While we could leave such cases
     856                 :             :                                  * to be detected as incorrect token sequences, the resulting
     857                 :             :                                  * message wouldn't be as helpful.  (We could also give the
     858                 :             :                                  * incorrect-quoting error when next is '{', but treating that
     859                 :             :                                  * as a token sequence error seems better.)
     860                 :             :                                  */
     861         [ -  + ]:        1365 :                                 while (*(++p) != '\0')
     862                 :             :                                 {
     863   [ +  +  +  +  :        1365 :                                         if (*p == typdelim || *p == '}' || *p == '{')
                   +  + ]
     864                 :             :                                         {
     865                 :        1357 :                                                 *srcptr = p;
     866                 :        1357 :                                                 return ATOK_ELEM;
     867                 :             :                                         }
     868         [ +  + ]:          12 :                                         if (!scanner_isspace(*p))
     869         [ +  + ]:           6 :                                                 ereturn(escontext, ATOK_ERROR,
     870                 :             :                                                                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     871                 :             :                                                                  errmsg("malformed array literal: \"%s\"", origStr),
     872                 :             :                                                                  errdetail("Incorrectly quoted array element.")));
     873                 :             :                                 }
     874                 :           0 :                                 goto ending_error;
     875                 :             :                         default:
     876                 :        8293 :                                 appendStringInfoChar(elembuf, *p++);
     877                 :        8293 :                                 break;
     878                 :             :                 }
     879                 :             :         }
     880                 :             : 
     881                 :             : unquoted_element:
     882                 :             : 
     883                 :             :         /*
     884                 :             :          * We don't include trailing whitespace in the result.  dstlen tracks how
     885                 :             :          * much of the output string is known to not be trailing whitespace.
     886                 :             :          */
     887                 :       31248 :         dstlen = 0;
     888                 :       31248 :         has_escapes = false;
     889                 :      157707 :         for (;;)
     890                 :             :         {
     891   [ +  +  +  +  :      157707 :                 switch (*p)
                      + ]
     892                 :             :                 {
     893                 :             :                         case '\0':
     894                 :           1 :                                 goto ending_error;
     895                 :             :                         case '{':
     896         [ +  + ]:           2 :                                 ereturn(escontext, ATOK_ERROR,
     897                 :             :                                                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     898                 :             :                                                  errmsg("malformed array literal: \"%s\"", origStr),
     899                 :             :                                                  errdetail("Unexpected \"%c\" character.",
     900                 :             :                                                                    '{')));
     901                 :             :                         case '"':
     902                 :             :                                 /* Must double-quote all or none of an element. */
     903         [ +  + ]:           2 :                                 ereturn(escontext, ATOK_ERROR,
     904                 :             :                                                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     905                 :             :                                                  errmsg("malformed array literal: \"%s\"", origStr),
     906                 :             :                                                  errdetail("Incorrectly quoted array element.")));
     907                 :             :                         case '\\':
     908                 :             :                                 /* Skip backslash, copy next character as-is. */
     909                 :           3 :                                 p++;
     910         [ +  - ]:           3 :                                 if (*p == '\0')
     911                 :           0 :                                         goto ending_error;
     912                 :           3 :                                 appendStringInfoChar(elembuf, *p++);
     913                 :           3 :                                 dstlen = elembuf->len;       /* treat it as non-whitespace */
     914                 :           3 :                                 has_escapes = true;
     915                 :           3 :                                 break;
     916                 :             :                         default:
     917                 :             :                                 /* End of elem? */
     918   [ +  +  +  + ]:      157699 :                                 if (*p == typdelim || *p == '}')
     919                 :             :                                 {
     920                 :             :                                         /* hack: truncate the output string to dstlen */
     921                 :       31243 :                                         elembuf->data[dstlen] = '\0';
     922                 :       31243 :                                         elembuf->len = dstlen;
     923                 :       31243 :                                         *srcptr = p;
     924                 :             :                                         /* Check if it's unquoted "NULL" */
     925   [ +  -  +  +  :       31243 :                                         if (Array_nulls && !has_escapes &&
                   +  + ]
     926                 :       31240 :                                                 pg_strcasecmp(elembuf->data, "NULL") == 0)
     927                 :          67 :                                                 return ATOK_ELEM_NULL;
     928                 :             :                                         else
     929                 :       31176 :                                                 return ATOK_ELEM;
     930                 :             :                                 }
     931                 :      126456 :                                 appendStringInfoChar(elembuf, *p);
     932         [ +  + ]:      126456 :                                 if (!scanner_isspace(*p))
     933                 :      126368 :                                         dstlen = elembuf->len;
     934                 :      126456 :                                 p++;
     935                 :      126456 :                                 break;
     936                 :             :                 }
     937                 :             :         }
     938                 :             : 
     939                 :             : ending_error:
     940         [ +  - ]:           1 :         ereturn(escontext, ATOK_ERROR,
     941                 :             :                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     942                 :             :                          errmsg("malformed array literal: \"%s\"", origStr),
     943                 :             :                          errdetail("Unexpected end of input.")));
     944         [ -  + ]:       70665 : }
     945                 :             : 
     946                 :             : /*
     947                 :             :  * Copy data into an array object from a temporary array of Datums.
     948                 :             :  *
     949                 :             :  * array: array object (with header fields already filled in)
     950                 :             :  * values: array of Datums to be copied
     951                 :             :  * nulls: array of is-null flags (can be NULL if no nulls)
     952                 :             :  * nitems: number of Datums to be copied
     953                 :             :  * typbyval, typlen, typalign: info about element datatype
     954                 :             :  * freedata: if true and element type is pass-by-ref, pfree data values
     955                 :             :  * referenced by Datums after copying them.
     956                 :             :  *
     957                 :             :  * If the input data is of varlena type, the caller must have ensured that
     958                 :             :  * the values are not toasted.  (Doing it here doesn't work since the
     959                 :             :  * caller has already allocated space for the array...)
     960                 :             :  */
     961                 :             : void
     962                 :      146873 : CopyArrayEls(ArrayType *array,
     963                 :             :                          const Datum *values,
     964                 :             :                          const bool *nulls,
     965                 :             :                          int nitems,
     966                 :             :                          int typlen,
     967                 :             :                          bool typbyval,
     968                 :             :                          char typalign,
     969                 :             :                          bool freedata)
     970                 :             : {
     971         [ +  + ]:      146873 :         char       *p = ARR_DATA_PTR(array);
     972         [ +  + ]:      146873 :         bits8      *bitmap = ARR_NULLBITMAP(array);
     973                 :      146873 :         int                     bitval = 0;
     974                 :      146873 :         int                     bitmask = 1;
     975                 :      146873 :         int                     i;
     976                 :             : 
     977         [ +  + ]:      146873 :         if (typbyval)
     978                 :      122581 :                 freedata = false;
     979                 :             : 
     980         [ +  + ]:      926619 :         for (i = 0; i < nitems; i++)
     981                 :             :         {
     982   [ +  +  +  + ]:      779746 :                 if (nulls && nulls[i])
     983                 :             :                 {
     984         [ +  - ]:        5488 :                         if (!bitmap)            /* shouldn't happen */
     985   [ #  #  #  # ]:           0 :                                 elog(ERROR, "null array element where not supported");
     986                 :             :                         /* bitmap bit stays 0 */
     987                 :        5488 :                 }
     988                 :             :                 else
     989                 :             :                 {
     990                 :      774258 :                         bitval |= bitmask;
     991                 :      774258 :                         p += ArrayCastAndSet(values[i], typlen, typbyval, typalign, p);
     992         [ +  + ]:      774258 :                         if (freedata)
     993                 :        5873 :                                 pfree(DatumGetPointer(values[i]));
     994                 :             :                 }
     995         [ +  + ]:      779746 :                 if (bitmap)
     996                 :             :                 {
     997                 :      130536 :                         bitmask <<= 1;
     998         [ +  + ]:      130536 :                         if (bitmask == 0x100)
     999                 :             :                         {
    1000                 :       15810 :                                 *bitmap++ = bitval;
    1001                 :       15810 :                                 bitval = 0;
    1002                 :       15810 :                                 bitmask = 1;
    1003                 :       15810 :                         }
    1004                 :      130536 :                 }
    1005                 :      779746 :         }
    1006                 :             : 
    1007   [ +  +  +  + ]:      146873 :         if (bitmap && bitmask != 1)
    1008                 :        2935 :                 *bitmap = bitval;
    1009                 :      146873 : }
    1010                 :             : 
    1011                 :             : /*
    1012                 :             :  * array_out :
    1013                 :             :  *                 takes the internal representation of an array and returns a string
    1014                 :             :  *                containing the array in its external format.
    1015                 :             :  */
    1016                 :             : Datum
    1017                 :        4540 : array_out(PG_FUNCTION_ARGS)
    1018                 :             : {
    1019                 :        4540 :         AnyArrayType *v = PG_GETARG_ANY_ARRAY_P(0);
    1020         [ +  + ]:        4540 :         Oid                     element_type = AARR_ELEMTYPE(v);
    1021                 :        4540 :         int                     typlen;
    1022                 :        4540 :         bool            typbyval;
    1023                 :        4540 :         char            typalign;
    1024                 :        4540 :         char            typdelim;
    1025                 :        4540 :         char       *p,
    1026                 :             :                            *tmp,
    1027                 :             :                            *retval,
    1028                 :             :                           **values,
    1029                 :             :                                 dims_str[(MAXDIM * 33) + 2];
    1030                 :             : 
    1031                 :             :         /*
    1032                 :             :          * 33 per dim since we assume 15 digits per number + ':' +'[]'
    1033                 :             :          *
    1034                 :             :          * +2 allows for assignment operator + trailing null
    1035                 :             :          */
    1036                 :        4540 :         bool       *needquotes,
    1037                 :        4540 :                                 needdims = false;
    1038                 :        4540 :         size_t          overall_length;
    1039                 :        4540 :         int                     nitems,
    1040                 :             :                                 i,
    1041                 :             :                                 j,
    1042                 :             :                                 k,
    1043                 :             :                                 indx[MAXDIM];
    1044                 :        4540 :         int                     ndim,
    1045                 :             :                            *dims,
    1046                 :             :                            *lb;
    1047                 :        4540 :         array_iter      iter;
    1048                 :        4540 :         ArrayMetaState *my_extra;
    1049                 :             : 
    1050                 :             :         /*
    1051                 :             :          * We arrange to look up info about element type, including its output
    1052                 :             :          * conversion proc, only once per series of calls, assuming the element
    1053                 :             :          * type doesn't change underneath us.
    1054                 :             :          */
    1055                 :        4540 :         my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
    1056         [ +  + ]:        4540 :         if (my_extra == NULL)
    1057                 :             :         {
    1058                 :        2520 :                 fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
    1059                 :             :                                                                                                           sizeof(ArrayMetaState));
    1060                 :        2520 :                 my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
    1061                 :        2520 :                 my_extra->element_type = ~element_type;
    1062                 :        2520 :         }
    1063                 :             : 
    1064         [ +  + ]:        4540 :         if (my_extra->element_type != element_type)
    1065                 :             :         {
    1066                 :             :                 /*
    1067                 :             :                  * Get info about element type, including its output conversion proc
    1068                 :             :                  */
    1069                 :        5080 :                 get_type_io_data(element_type, IOFunc_output,
    1070                 :        2540 :                                                  &my_extra->typlen, &my_extra->typbyval,
    1071                 :        2540 :                                                  &my_extra->typalign, &my_extra->typdelim,
    1072                 :        2540 :                                                  &my_extra->typioparam, &my_extra->typiofunc);
    1073                 :        5080 :                 fmgr_info_cxt(my_extra->typiofunc, &my_extra->proc,
    1074                 :        2540 :                                           fcinfo->flinfo->fn_mcxt);
    1075                 :        2540 :                 my_extra->element_type = element_type;
    1076                 :        2540 :         }
    1077                 :        4540 :         typlen = my_extra->typlen;
    1078                 :        4540 :         typbyval = my_extra->typbyval;
    1079                 :        4540 :         typalign = my_extra->typalign;
    1080                 :        4540 :         typdelim = my_extra->typdelim;
    1081                 :             : 
    1082         [ +  + ]:        4540 :         ndim = AARR_NDIM(v);
    1083         [ +  + ]:        4540 :         dims = AARR_DIMS(v);
    1084         [ +  + ]:        4540 :         lb = AARR_LBOUND(v);
    1085                 :        4540 :         nitems = ArrayGetNItems(ndim, dims);
    1086                 :             : 
    1087         [ +  + ]:        4540 :         if (nitems == 0)
    1088                 :             :         {
    1089                 :         358 :                 retval = pstrdup("{}");
    1090                 :         358 :                 PG_RETURN_CSTRING(retval);
    1091                 :             :         }
    1092                 :             : 
    1093                 :             :         /*
    1094                 :             :          * we will need to add explicit dimensions if any dimension has a lower
    1095                 :             :          * bound other than one
    1096                 :             :          */
    1097         [ +  + ]:        8452 :         for (i = 0; i < ndim; i++)
    1098                 :             :         {
    1099         [ +  + ]:        4318 :                 if (lb[i] != 1)
    1100                 :             :                 {
    1101                 :          48 :                         needdims = true;
    1102                 :          48 :                         break;
    1103                 :             :                 }
    1104                 :        4270 :         }
    1105                 :             : 
    1106                 :             :         /*
    1107                 :             :          * Convert all values to string form, count total space needed (including
    1108                 :             :          * any overhead such as escaping backslashes), and detect whether each
    1109                 :             :          * item needs double quotes.
    1110                 :             :          */
    1111                 :        4182 :         values = (char **) palloc(nitems * sizeof(char *));
    1112                 :        4182 :         needquotes = (bool *) palloc(nitems * sizeof(bool));
    1113                 :        4182 :         overall_length = 0;
    1114                 :             : 
    1115                 :        4182 :         array_iter_setup(&iter, v);
    1116                 :             : 
    1117         [ +  + ]:       30780 :         for (i = 0; i < nitems; i++)
    1118                 :             :         {
    1119                 :       26598 :                 Datum           itemvalue;
    1120                 :       26598 :                 bool            isnull;
    1121                 :       26598 :                 bool            needquote;
    1122                 :             : 
    1123                 :             :                 /* Get source element, checking for NULL */
    1124                 :       53196 :                 itemvalue = array_iter_next(&iter, &isnull, i,
    1125                 :       26598 :                                                                         typlen, typbyval, typalign);
    1126                 :             : 
    1127         [ +  + ]:       26598 :                 if (isnull)
    1128                 :             :                 {
    1129                 :         335 :                         values[i] = pstrdup("NULL");
    1130                 :         335 :                         overall_length += 4;
    1131                 :         335 :                         needquote = false;
    1132                 :         335 :                 }
    1133                 :             :                 else
    1134                 :             :                 {
    1135                 :       26263 :                         values[i] = OutputFunctionCall(&my_extra->proc, itemvalue);
    1136                 :             : 
    1137                 :             :                         /* count data plus backslashes; detect chars needing quotes */
    1138         [ +  + ]:       26263 :                         if (values[i][0] == '\0')
    1139                 :          46 :                                 needquote = true;       /* force quotes for empty string */
    1140         [ +  + ]:       26217 :                         else if (pg_strcasecmp(values[i], "NULL") == 0)
    1141                 :           2 :                                 needquote = true;       /* force quotes for literal NULL */
    1142                 :             :                         else
    1143                 :       26215 :                                 needquote = false;
    1144                 :             : 
    1145         [ +  + ]:      179913 :                         for (tmp = values[i]; *tmp != '\0'; tmp++)
    1146                 :             :                         {
    1147                 :      153650 :                                 char            ch = *tmp;
    1148                 :             : 
    1149                 :      153650 :                                 overall_length += 1;
    1150   [ +  +  +  + ]:      153650 :                                 if (ch == '"' || ch == '\\')
    1151                 :             :                                 {
    1152                 :         237 :                                         needquote = true;
    1153                 :         237 :                                         overall_length += 1;
    1154                 :         237 :                                 }
    1155   [ +  +  +  +  :      153413 :                                 else if (ch == '{' || ch == '}' || ch == typdelim ||
             +  +  +  + ]
    1156                 :      152195 :                                                  scanner_isspace(ch))
    1157                 :        1498 :                                         needquote = true;
    1158                 :      153650 :                         }
    1159                 :             :                 }
    1160                 :             : 
    1161                 :       26598 :                 needquotes[i] = needquote;
    1162                 :             : 
    1163                 :             :                 /* Count the pair of double quotes, if needed */
    1164         [ +  + ]:       26598 :                 if (needquote)
    1165                 :         998 :                         overall_length += 2;
    1166                 :             :                 /* and the comma (or other typdelim delimiter) */
    1167                 :       26598 :                 overall_length += 1;
    1168                 :       26598 :         }
    1169                 :             : 
    1170                 :             :         /*
    1171                 :             :          * The very last array element doesn't have a typdelim delimiter after it,
    1172                 :             :          * but that's OK; that space is needed for the trailing '\0'.
    1173                 :             :          *
    1174                 :             :          * Now count total number of curly brace pairs in output string.
    1175                 :             :          */
    1176         [ +  + ]:        8511 :         for (i = j = 0, k = 1; i < ndim; i++)
    1177                 :             :         {
    1178                 :        4329 :                 j += k, k *= dims[i];
    1179                 :        4329 :         }
    1180                 :        4182 :         overall_length += 2 * j;
    1181                 :             : 
    1182                 :             :         /* Format explicit dimensions if required */
    1183                 :        4182 :         dims_str[0] = '\0';
    1184         [ +  + ]:        4182 :         if (needdims)
    1185                 :             :         {
    1186                 :          48 :                 char       *ptr = dims_str;
    1187                 :             : 
    1188         [ +  + ]:         107 :                 for (i = 0; i < ndim; i++)
    1189                 :             :                 {
    1190                 :          59 :                         sprintf(ptr, "[%d:%d]", lb[i], lb[i] + dims[i] - 1);
    1191                 :          59 :                         ptr += strlen(ptr);
    1192                 :          59 :                 }
    1193                 :          48 :                 *ptr++ = *ASSGN;
    1194                 :          48 :                 *ptr = '\0';
    1195                 :          48 :                 overall_length += ptr - dims_str;
    1196                 :          48 :         }
    1197                 :             : 
    1198                 :             :         /* Now construct the output string */
    1199                 :        4182 :         retval = (char *) palloc(overall_length);
    1200                 :        4182 :         p = retval;
    1201                 :             : 
    1202                 :             : #define APPENDSTR(str)  (strcpy(p, (str)), p += strlen(p))
    1203                 :             : #define APPENDCHAR(ch)  (*p++ = (ch), *p = '\0')
    1204                 :             : 
    1205         [ +  + ]:        4182 :         if (needdims)
    1206                 :          48 :                 APPENDSTR(dims_str);
    1207                 :        4182 :         APPENDCHAR('{');
    1208         [ +  + ]:        8511 :         for (i = 0; i < ndim; i++)
    1209                 :        4329 :                 indx[i] = 0;
    1210                 :        4182 :         j = 0;
    1211                 :        4182 :         k = 0;
    1212                 :        4182 :         do
    1213                 :             :         {
    1214         [ +  + ]:       26912 :                 for (i = j; i < ndim - 1; i++)
    1215                 :         314 :                         APPENDCHAR('{');
    1216                 :             : 
    1217         [ +  + ]:       26598 :                 if (needquotes[k])
    1218                 :             :                 {
    1219                 :         998 :                         APPENDCHAR('"');
    1220         [ +  + ]:        8295 :                         for (tmp = values[k]; *tmp; tmp++)
    1221                 :             :                         {
    1222                 :        7297 :                                 char            ch = *tmp;
    1223                 :             : 
    1224   [ +  +  +  + ]:        7297 :                                 if (ch == '"' || ch == '\\')
    1225                 :         237 :                                         *p++ = '\\';
    1226                 :        7297 :                                 *p++ = ch;
    1227                 :        7297 :                         }
    1228                 :         998 :                         *p = '\0';
    1229                 :         998 :                         APPENDCHAR('"');
    1230                 :         998 :                 }
    1231                 :             :                 else
    1232                 :       25600 :                         APPENDSTR(values[k]);
    1233                 :       26598 :                 pfree(values[k++]);
    1234                 :             : 
    1235         [ +  + ]:       31094 :                 for (i = ndim - 1; i >= 0; i--)
    1236                 :             :                 {
    1237         [ +  + ]:       26912 :                         if (++(indx[i]) < dims[i])
    1238                 :             :                         {
    1239                 :       22416 :                                 APPENDCHAR(typdelim);
    1240                 :       22416 :                                 break;
    1241                 :             :                         }
    1242                 :             :                         else
    1243                 :             :                         {
    1244                 :        4496 :                                 indx[i] = 0;
    1245                 :        4496 :                                 APPENDCHAR('}');
    1246                 :             :                         }
    1247                 :        4496 :                 }
    1248                 :       26598 :                 j = i;
    1249         [ +  + ]:       26598 :         } while (j != -1);
    1250                 :             : 
    1251                 :             : #undef APPENDSTR
    1252                 :             : #undef APPENDCHAR
    1253                 :             : 
    1254                 :             :         /* Assert that we calculated the string length accurately */
    1255         [ +  - ]:        4182 :         Assert(overall_length == (p - retval + 1));
    1256                 :             : 
    1257                 :        4182 :         pfree(values);
    1258                 :        4182 :         pfree(needquotes);
    1259                 :             : 
    1260                 :        4182 :         PG_RETURN_CSTRING(retval);
    1261                 :        4540 : }
    1262                 :             : 
    1263                 :             : /*
    1264                 :             :  * array_recv :
    1265                 :             :  *                converts an array from the external binary format to
    1266                 :             :  *                its internal format.
    1267                 :             :  *
    1268                 :             :  * return value :
    1269                 :             :  *                the internal representation of the input array
    1270                 :             :  */
    1271                 :             : Datum
    1272                 :           0 : array_recv(PG_FUNCTION_ARGS)
    1273                 :             : {
    1274                 :           0 :         StringInfo      buf = (StringInfo) PG_GETARG_POINTER(0);
    1275                 :           0 :         Oid                     spec_element_type = PG_GETARG_OID(1);   /* type of an array
    1276                 :             :                                                                                                                  * element */
    1277                 :           0 :         int32           typmod = PG_GETARG_INT32(2);    /* typmod for array elements */
    1278                 :           0 :         Oid                     element_type;
    1279                 :           0 :         int                     typlen;
    1280                 :           0 :         bool            typbyval;
    1281                 :           0 :         char            typalign;
    1282                 :           0 :         Oid                     typioparam;
    1283                 :           0 :         int                     i,
    1284                 :             :                                 nitems;
    1285                 :           0 :         Datum      *dataPtr;
    1286                 :           0 :         bool       *nullsPtr;
    1287                 :           0 :         bool            hasnulls;
    1288                 :           0 :         int32           nbytes;
    1289                 :           0 :         int32           dataoffset;
    1290                 :           0 :         ArrayType  *retval;
    1291                 :           0 :         int                     ndim,
    1292                 :             :                                 flags,
    1293                 :             :                                 dim[MAXDIM],
    1294                 :             :                                 lBound[MAXDIM];
    1295                 :           0 :         ArrayMetaState *my_extra;
    1296                 :             : 
    1297                 :             :         /* Get the array header information */
    1298                 :           0 :         ndim = pq_getmsgint(buf, 4);
    1299         [ #  # ]:           0 :         if (ndim < 0)                                /* we do allow zero-dimension arrays */
    1300   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1301                 :             :                                 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
    1302                 :             :                                  errmsg("invalid number of dimensions: %d", ndim)));
    1303         [ #  # ]:           0 :         if (ndim > MAXDIM)
    1304   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1305                 :             :                                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    1306                 :             :                                  errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
    1307                 :             :                                                 ndim, MAXDIM)));
    1308                 :             : 
    1309                 :           0 :         flags = pq_getmsgint(buf, 4);
    1310   [ #  #  #  # ]:           0 :         if (flags != 0 && flags != 1)
    1311   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1312                 :             :                                 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
    1313                 :             :                                  errmsg("invalid array flags")));
    1314                 :             : 
    1315                 :             :         /* Check element type recorded in the data */
    1316                 :           0 :         element_type = pq_getmsgint(buf, sizeof(Oid));
    1317                 :             : 
    1318                 :             :         /*
    1319                 :             :          * From a security standpoint, it doesn't matter whether the input's
    1320                 :             :          * element type matches what we expect: the element type's receive
    1321                 :             :          * function has to be robust enough to cope with invalid data.  However,
    1322                 :             :          * from a user-friendliness standpoint, it's nicer to complain about type
    1323                 :             :          * mismatches than to throw "improper binary format" errors.  But there's
    1324                 :             :          * a problem: only built-in types have OIDs that are stable enough to
    1325                 :             :          * believe that a mismatch is a real issue.  So complain only if both OIDs
    1326                 :             :          * are in the built-in range.  Otherwise, carry on with the element type
    1327                 :             :          * we "should" be getting.
    1328                 :             :          */
    1329         [ #  # ]:           0 :         if (element_type != spec_element_type)
    1330                 :             :         {
    1331   [ #  #  #  # ]:           0 :                 if (element_type < FirstGenbkiObjectId &&
    1332                 :           0 :                         spec_element_type < FirstGenbkiObjectId)
    1333   [ #  #  #  # ]:           0 :                         ereport(ERROR,
    1334                 :             :                                         (errcode(ERRCODE_DATATYPE_MISMATCH),
    1335                 :             :                                          errmsg("binary data has array element type %u (%s) instead of expected %u (%s)",
    1336                 :             :                                                         element_type,
    1337                 :             :                                                         format_type_extended(element_type, -1,
    1338                 :             :                                                                                                  FORMAT_TYPE_ALLOW_INVALID),
    1339                 :             :                                                         spec_element_type,
    1340                 :             :                                                         format_type_extended(spec_element_type, -1,
    1341                 :             :                                                                                                  FORMAT_TYPE_ALLOW_INVALID))));
    1342                 :           0 :                 element_type = spec_element_type;
    1343                 :           0 :         }
    1344                 :             : 
    1345         [ #  # ]:           0 :         for (i = 0; i < ndim; i++)
    1346                 :             :         {
    1347                 :           0 :                 dim[i] = pq_getmsgint(buf, 4);
    1348                 :           0 :                 lBound[i] = pq_getmsgint(buf, 4);
    1349                 :           0 :         }
    1350                 :             : 
    1351                 :             :         /* This checks for overflow of array dimensions */
    1352                 :           0 :         nitems = ArrayGetNItems(ndim, dim);
    1353                 :           0 :         ArrayCheckBounds(ndim, dim, lBound);
    1354                 :             : 
    1355                 :             :         /*
    1356                 :             :          * We arrange to look up info about element type, including its receive
    1357                 :             :          * conversion proc, only once per series of calls, assuming the element
    1358                 :             :          * type doesn't change underneath us.
    1359                 :             :          */
    1360                 :           0 :         my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
    1361         [ #  # ]:           0 :         if (my_extra == NULL)
    1362                 :             :         {
    1363                 :           0 :                 fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
    1364                 :             :                                                                                                           sizeof(ArrayMetaState));
    1365                 :           0 :                 my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
    1366                 :           0 :                 my_extra->element_type = ~element_type;
    1367                 :           0 :         }
    1368                 :             : 
    1369         [ #  # ]:           0 :         if (my_extra->element_type != element_type)
    1370                 :             :         {
    1371                 :             :                 /* Get info about element type, including its receive proc */
    1372                 :           0 :                 get_type_io_data(element_type, IOFunc_receive,
    1373                 :           0 :                                                  &my_extra->typlen, &my_extra->typbyval,
    1374                 :           0 :                                                  &my_extra->typalign, &my_extra->typdelim,
    1375                 :           0 :                                                  &my_extra->typioparam, &my_extra->typiofunc);
    1376         [ #  # ]:           0 :                 if (!OidIsValid(my_extra->typiofunc))
    1377   [ #  #  #  # ]:           0 :                         ereport(ERROR,
    1378                 :             :                                         (errcode(ERRCODE_UNDEFINED_FUNCTION),
    1379                 :             :                                          errmsg("no binary input function available for type %s",
    1380                 :             :                                                         format_type_be(element_type))));
    1381                 :           0 :                 fmgr_info_cxt(my_extra->typiofunc, &my_extra->proc,
    1382                 :           0 :                                           fcinfo->flinfo->fn_mcxt);
    1383                 :           0 :                 my_extra->element_type = element_type;
    1384                 :           0 :         }
    1385                 :             : 
    1386         [ #  # ]:           0 :         if (nitems == 0)
    1387                 :             :         {
    1388                 :             :                 /* Return empty array ... but not till we've validated element_type */
    1389                 :           0 :                 PG_RETURN_ARRAYTYPE_P(construct_empty_array(element_type));
    1390                 :             :         }
    1391                 :             : 
    1392                 :           0 :         typlen = my_extra->typlen;
    1393                 :           0 :         typbyval = my_extra->typbyval;
    1394                 :           0 :         typalign = my_extra->typalign;
    1395                 :           0 :         typioparam = my_extra->typioparam;
    1396                 :             : 
    1397                 :           0 :         dataPtr = (Datum *) palloc(nitems * sizeof(Datum));
    1398                 :           0 :         nullsPtr = (bool *) palloc(nitems * sizeof(bool));
    1399                 :           0 :         ReadArrayBinary(buf, nitems,
    1400                 :           0 :                                         &my_extra->proc, typioparam, typmod,
    1401                 :           0 :                                         typlen, typbyval, typalign,
    1402                 :           0 :                                         dataPtr, nullsPtr,
    1403                 :             :                                         &hasnulls, &nbytes);
    1404         [ #  # ]:           0 :         if (hasnulls)
    1405                 :             :         {
    1406                 :           0 :                 dataoffset = ARR_OVERHEAD_WITHNULLS(ndim, nitems);
    1407                 :           0 :                 nbytes += dataoffset;
    1408                 :           0 :         }
    1409                 :             :         else
    1410                 :             :         {
    1411                 :           0 :                 dataoffset = 0;                 /* marker for no null bitmap */
    1412                 :           0 :                 nbytes += ARR_OVERHEAD_NONULLS(ndim);
    1413                 :             :         }
    1414                 :           0 :         retval = (ArrayType *) palloc0(nbytes);
    1415                 :           0 :         SET_VARSIZE(retval, nbytes);
    1416                 :           0 :         retval->ndim = ndim;
    1417                 :           0 :         retval->dataoffset = dataoffset;
    1418                 :           0 :         retval->elemtype = element_type;
    1419                 :           0 :         memcpy(ARR_DIMS(retval), dim, ndim * sizeof(int));
    1420                 :           0 :         memcpy(ARR_LBOUND(retval), lBound, ndim * sizeof(int));
    1421                 :             : 
    1422                 :           0 :         CopyArrayEls(retval,
    1423                 :           0 :                                  dataPtr, nullsPtr, nitems,
    1424                 :           0 :                                  typlen, typbyval, typalign,
    1425                 :             :                                  true);
    1426                 :             : 
    1427                 :           0 :         pfree(dataPtr);
    1428                 :           0 :         pfree(nullsPtr);
    1429                 :             : 
    1430                 :           0 :         PG_RETURN_ARRAYTYPE_P(retval);
    1431                 :           0 : }
    1432                 :             : 
    1433                 :             : /*
    1434                 :             :  * ReadArrayBinary:
    1435                 :             :  *       collect the data elements of an array being read in binary style.
    1436                 :             :  *
    1437                 :             :  * Inputs:
    1438                 :             :  *      buf: the data buffer to read from.
    1439                 :             :  *      nitems: total number of array elements (already read).
    1440                 :             :  *      receiveproc: type-specific receive procedure for element datatype.
    1441                 :             :  *      typioparam, typmod: auxiliary values to pass to receiveproc.
    1442                 :             :  *      typlen, typbyval, typalign: storage parameters of element datatype.
    1443                 :             :  *
    1444                 :             :  * Outputs:
    1445                 :             :  *      values[]: filled with converted data values.
    1446                 :             :  *      nulls[]: filled with is-null markers.
    1447                 :             :  *      *hasnulls: set true iff there are any null elements.
    1448                 :             :  *      *nbytes: set to total size of data area needed (including alignment
    1449                 :             :  *              padding but not including array header overhead).
    1450                 :             :  *
    1451                 :             :  * Note that values[] and nulls[] are allocated by the caller, and must have
    1452                 :             :  * nitems elements.
    1453                 :             :  */
    1454                 :             : static void
    1455                 :           0 : ReadArrayBinary(StringInfo buf,
    1456                 :             :                                 int nitems,
    1457                 :             :                                 FmgrInfo *receiveproc,
    1458                 :             :                                 Oid typioparam,
    1459                 :             :                                 int32 typmod,
    1460                 :             :                                 int typlen,
    1461                 :             :                                 bool typbyval,
    1462                 :             :                                 char typalign,
    1463                 :             :                                 Datum *values,
    1464                 :             :                                 bool *nulls,
    1465                 :             :                                 bool *hasnulls,
    1466                 :             :                                 int32 *nbytes)
    1467                 :             : {
    1468                 :           0 :         int                     i;
    1469                 :           0 :         bool            hasnull;
    1470                 :           0 :         int32           totbytes;
    1471                 :             : 
    1472         [ #  # ]:           0 :         for (i = 0; i < nitems; i++)
    1473                 :             :         {
    1474                 :           0 :                 int                     itemlen;
    1475                 :           0 :                 StringInfoData elem_buf;
    1476                 :             : 
    1477                 :             :                 /* Get and check the item length */
    1478                 :           0 :                 itemlen = pq_getmsgint(buf, 4);
    1479         [ #  # ]:           0 :                 if (itemlen < -1 || itemlen > (buf->len - buf->cursor))
    1480   [ #  #  #  # ]:           0 :                         ereport(ERROR,
    1481                 :             :                                         (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
    1482                 :             :                                          errmsg("insufficient data left in message")));
    1483                 :             : 
    1484         [ #  # ]:           0 :                 if (itemlen == -1)
    1485                 :             :                 {
    1486                 :             :                         /* -1 length means NULL */
    1487                 :           0 :                         values[i] = ReceiveFunctionCall(receiveproc, NULL,
    1488                 :           0 :                                                                                         typioparam, typmod);
    1489                 :           0 :                         nulls[i] = true;
    1490                 :           0 :                         continue;
    1491                 :             :                 }
    1492                 :             : 
    1493                 :             :                 /*
    1494                 :             :                  * Rather than copying data around, we just initialize a StringInfo
    1495                 :             :                  * pointing to the correct portion of the message buffer.
    1496                 :             :                  */
    1497                 :           0 :                 initReadOnlyStringInfo(&elem_buf, &buf->data[buf->cursor], itemlen);
    1498                 :             : 
    1499                 :           0 :                 buf->cursor += itemlen;
    1500                 :             : 
    1501                 :             :                 /* Now call the element's receiveproc */
    1502                 :           0 :                 values[i] = ReceiveFunctionCall(receiveproc, &elem_buf,
    1503                 :           0 :                                                                                 typioparam, typmod);
    1504                 :           0 :                 nulls[i] = false;
    1505                 :             : 
    1506                 :             :                 /* Trouble if it didn't eat the whole buffer */
    1507         [ #  # ]:           0 :                 if (elem_buf.cursor != itemlen)
    1508   [ #  #  #  # ]:           0 :                         ereport(ERROR,
    1509                 :             :                                         (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
    1510                 :             :                                          errmsg("improper binary format in array element %d",
    1511                 :             :                                                         i + 1)));
    1512      [ #  #  # ]:           0 :         }
    1513                 :             : 
    1514                 :             :         /*
    1515                 :             :          * Check for nulls, compute total data space needed
    1516                 :             :          */
    1517                 :           0 :         hasnull = false;
    1518                 :           0 :         totbytes = 0;
    1519         [ #  # ]:           0 :         for (i = 0; i < nitems; i++)
    1520                 :             :         {
    1521         [ #  # ]:           0 :                 if (nulls[i])
    1522                 :           0 :                         hasnull = true;
    1523                 :             :                 else
    1524                 :             :                 {
    1525                 :             :                         /* let's just make sure data is not toasted */
    1526         [ #  # ]:           0 :                         if (typlen == -1)
    1527                 :           0 :                                 values[i] = PointerGetDatum(PG_DETOAST_DATUM(values[i]));
    1528   [ #  #  #  #  :           0 :                         totbytes = att_addlength_datum(totbytes, typlen, values[i]);
                   #  # ]
    1529   [ #  #  #  #  :           0 :                         totbytes = att_align_nominal(totbytes, typalign);
             #  #  #  # ]
    1530                 :             :                         /* check for overflow of total request */
    1531         [ #  # ]:           0 :                         if (!AllocSizeIsValid(totbytes))
    1532   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
    1533                 :             :                                                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    1534                 :             :                                                  errmsg("array size exceeds the maximum allowed (%zu)",
    1535                 :             :                                                                 MaxAllocSize)));
    1536                 :             :                 }
    1537                 :           0 :         }
    1538                 :           0 :         *hasnulls = hasnull;
    1539                 :           0 :         *nbytes = totbytes;
    1540                 :           0 : }
    1541                 :             : 
    1542                 :             : 
    1543                 :             : /*
    1544                 :             :  * array_send :
    1545                 :             :  *                takes the internal representation of an array and returns a bytea
    1546                 :             :  *                containing the array in its external binary format.
    1547                 :             :  */
    1548                 :             : Datum
    1549                 :           0 : array_send(PG_FUNCTION_ARGS)
    1550                 :             : {
    1551                 :           0 :         AnyArrayType *v = PG_GETARG_ANY_ARRAY_P(0);
    1552         [ #  # ]:           0 :         Oid                     element_type = AARR_ELEMTYPE(v);
    1553                 :           0 :         int                     typlen;
    1554                 :           0 :         bool            typbyval;
    1555                 :           0 :         char            typalign;
    1556                 :           0 :         int                     nitems,
    1557                 :             :                                 i;
    1558                 :           0 :         int                     ndim,
    1559                 :             :                            *dim,
    1560                 :             :                            *lb;
    1561                 :           0 :         StringInfoData buf;
    1562                 :           0 :         array_iter      iter;
    1563                 :           0 :         ArrayMetaState *my_extra;
    1564                 :             : 
    1565                 :             :         /*
    1566                 :             :          * We arrange to look up info about element type, including its send
    1567                 :             :          * conversion proc, only once per series of calls, assuming the element
    1568                 :             :          * type doesn't change underneath us.
    1569                 :             :          */
    1570                 :           0 :         my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
    1571         [ #  # ]:           0 :         if (my_extra == NULL)
    1572                 :             :         {
    1573                 :           0 :                 fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
    1574                 :             :                                                                                                           sizeof(ArrayMetaState));
    1575                 :           0 :                 my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
    1576                 :           0 :                 my_extra->element_type = ~element_type;
    1577                 :           0 :         }
    1578                 :             : 
    1579         [ #  # ]:           0 :         if (my_extra->element_type != element_type)
    1580                 :             :         {
    1581                 :             :                 /* Get info about element type, including its send proc */
    1582                 :           0 :                 get_type_io_data(element_type, IOFunc_send,
    1583                 :           0 :                                                  &my_extra->typlen, &my_extra->typbyval,
    1584                 :           0 :                                                  &my_extra->typalign, &my_extra->typdelim,
    1585                 :           0 :                                                  &my_extra->typioparam, &my_extra->typiofunc);
    1586         [ #  # ]:           0 :                 if (!OidIsValid(my_extra->typiofunc))
    1587   [ #  #  #  # ]:           0 :                         ereport(ERROR,
    1588                 :             :                                         (errcode(ERRCODE_UNDEFINED_FUNCTION),
    1589                 :             :                                          errmsg("no binary output function available for type %s",
    1590                 :             :                                                         format_type_be(element_type))));
    1591                 :           0 :                 fmgr_info_cxt(my_extra->typiofunc, &my_extra->proc,
    1592                 :           0 :                                           fcinfo->flinfo->fn_mcxt);
    1593                 :           0 :                 my_extra->element_type = element_type;
    1594                 :           0 :         }
    1595                 :           0 :         typlen = my_extra->typlen;
    1596                 :           0 :         typbyval = my_extra->typbyval;
    1597                 :           0 :         typalign = my_extra->typalign;
    1598                 :             : 
    1599         [ #  # ]:           0 :         ndim = AARR_NDIM(v);
    1600         [ #  # ]:           0 :         dim = AARR_DIMS(v);
    1601         [ #  # ]:           0 :         lb = AARR_LBOUND(v);
    1602                 :           0 :         nitems = ArrayGetNItems(ndim, dim);
    1603                 :             : 
    1604                 :           0 :         pq_begintypsend(&buf);
    1605                 :             : 
    1606                 :             :         /* Send the array header information */
    1607                 :           0 :         pq_sendint32(&buf, ndim);
    1608   [ #  #  #  # ]:           0 :         pq_sendint32(&buf, AARR_HASNULL(v) ? 1 : 0);
    1609                 :           0 :         pq_sendint32(&buf, element_type);
    1610         [ #  # ]:           0 :         for (i = 0; i < ndim; i++)
    1611                 :             :         {
    1612                 :           0 :                 pq_sendint32(&buf, dim[i]);
    1613                 :           0 :                 pq_sendint32(&buf, lb[i]);
    1614                 :           0 :         }
    1615                 :             : 
    1616                 :             :         /* Send the array elements using the element's own sendproc */
    1617                 :           0 :         array_iter_setup(&iter, v);
    1618                 :             : 
    1619         [ #  # ]:           0 :         for (i = 0; i < nitems; i++)
    1620                 :             :         {
    1621                 :           0 :                 Datum           itemvalue;
    1622                 :           0 :                 bool            isnull;
    1623                 :             : 
    1624                 :             :                 /* Get source element, checking for NULL */
    1625                 :           0 :                 itemvalue = array_iter_next(&iter, &isnull, i,
    1626                 :           0 :                                                                         typlen, typbyval, typalign);
    1627                 :             : 
    1628         [ #  # ]:           0 :                 if (isnull)
    1629                 :             :                 {
    1630                 :             :                         /* -1 length means a NULL */
    1631                 :           0 :                         pq_sendint32(&buf, -1);
    1632                 :           0 :                 }
    1633                 :             :                 else
    1634                 :             :                 {
    1635                 :           0 :                         bytea      *outputbytes;
    1636                 :             : 
    1637                 :           0 :                         outputbytes = SendFunctionCall(&my_extra->proc, itemvalue);
    1638                 :           0 :                         pq_sendint32(&buf, VARSIZE(outputbytes) - VARHDRSZ);
    1639                 :           0 :                         pq_sendbytes(&buf, VARDATA(outputbytes),
    1640                 :           0 :                                                  VARSIZE(outputbytes) - VARHDRSZ);
    1641                 :           0 :                         pfree(outputbytes);
    1642                 :           0 :                 }
    1643                 :           0 :         }
    1644                 :             : 
    1645                 :           0 :         PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
    1646                 :           0 : }
    1647                 :             : 
    1648                 :             : /*
    1649                 :             :  * array_ndims :
    1650                 :             :  *                returns the number of dimensions of the array pointed to by "v"
    1651                 :             :  */
    1652                 :             : Datum
    1653                 :         286 : array_ndims(PG_FUNCTION_ARGS)
    1654                 :             : {
    1655                 :         286 :         AnyArrayType *v = PG_GETARG_ANY_ARRAY_P(0);
    1656                 :             : 
    1657                 :             :         /* Sanity check: does it look like an array at all? */
    1658   [ +  -  +  +  :         286 :         if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
             +  -  -  + ]
    1659                 :           2 :                 PG_RETURN_NULL();
    1660                 :             : 
    1661         [ +  - ]:         284 :         PG_RETURN_INT32(AARR_NDIM(v));
    1662                 :         286 : }
    1663                 :             : 
    1664                 :             : /*
    1665                 :             :  * array_dims :
    1666                 :             :  *                returns the dimensions of the array pointed to by "v", as a "text"
    1667                 :             :  */
    1668                 :             : Datum
    1669                 :        1583 : array_dims(PG_FUNCTION_ARGS)
    1670                 :             : {
    1671                 :        1583 :         AnyArrayType *v = PG_GETARG_ANY_ARRAY_P(0);
    1672                 :        1583 :         char       *p;
    1673                 :        1583 :         int                     i;
    1674                 :        1583 :         int                *dimv,
    1675                 :             :                            *lb;
    1676                 :             : 
    1677                 :             :         /*
    1678                 :             :          * 33 since we assume 15 digits per number + ':' +'[]'
    1679                 :             :          *
    1680                 :             :          * +1 for trailing null
    1681                 :             :          */
    1682                 :        1583 :         char            buf[MAXDIM * 33 + 1];
    1683                 :             : 
    1684                 :             :         /* Sanity check: does it look like an array at all? */
    1685   [ +  -  +  +  :        1583 :         if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
             +  -  -  + ]
    1686                 :          11 :                 PG_RETURN_NULL();
    1687                 :             : 
    1688         [ +  - ]:        1572 :         dimv = AARR_DIMS(v);
    1689         [ +  - ]:        1572 :         lb = AARR_LBOUND(v);
    1690                 :             : 
    1691                 :        1572 :         p = buf;
    1692   [ +  -  +  + ]:        3162 :         for (i = 0; i < AARR_NDIM(v); i++)
    1693                 :             :         {
    1694                 :        1590 :                 sprintf(p, "[%d:%d]", lb[i], dimv[i] + lb[i] - 1);
    1695                 :        1590 :                 p += strlen(p);
    1696                 :        1590 :         }
    1697                 :             : 
    1698                 :        1572 :         PG_RETURN_TEXT_P(cstring_to_text(buf));
    1699                 :        1583 : }
    1700                 :             : 
    1701                 :             : /*
    1702                 :             :  * array_lower :
    1703                 :             :  *              returns the lower dimension, of the DIM requested, for
    1704                 :             :  *              the array pointed to by "v", as an int4
    1705                 :             :  */
    1706                 :             : Datum
    1707                 :        4319 : array_lower(PG_FUNCTION_ARGS)
    1708                 :             : {
    1709                 :        4319 :         AnyArrayType *v = PG_GETARG_ANY_ARRAY_P(0);
    1710                 :        4319 :         int                     reqdim = PG_GETARG_INT32(1);
    1711                 :        4319 :         int                *lb;
    1712                 :        4319 :         int                     result;
    1713                 :             : 
    1714                 :             :         /* Sanity check: does it look like an array at all? */
    1715   [ +  +  -  +  :        4319 :         if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
             +  +  -  + ]
    1716                 :           0 :                 PG_RETURN_NULL();
    1717                 :             : 
    1718                 :             :         /* Sanity check: was the requested dim valid */
    1719   [ -  +  +  +  :        4319 :         if (reqdim <= 0 || reqdim > AARR_NDIM(v))
                   -  + ]
    1720                 :           0 :                 PG_RETURN_NULL();
    1721                 :             : 
    1722         [ +  + ]:        4319 :         lb = AARR_LBOUND(v);
    1723                 :        4319 :         result = lb[reqdim - 1];
    1724                 :             : 
    1725                 :        4319 :         PG_RETURN_INT32(result);
    1726                 :        4319 : }
    1727                 :             : 
    1728                 :             : /*
    1729                 :             :  * array_upper :
    1730                 :             :  *              returns the upper dimension, of the DIM requested, for
    1731                 :             :  *              the array pointed to by "v", as an int4
    1732                 :             :  */
    1733                 :             : Datum
    1734                 :        4397 : array_upper(PG_FUNCTION_ARGS)
    1735                 :             : {
    1736                 :        4397 :         AnyArrayType *v = PG_GETARG_ANY_ARRAY_P(0);
    1737                 :        4397 :         int                     reqdim = PG_GETARG_INT32(1);
    1738                 :        4397 :         int                *dimv,
    1739                 :             :                            *lb;
    1740                 :        4397 :         int                     result;
    1741                 :             : 
    1742                 :             :         /* Sanity check: does it look like an array at all? */
    1743   [ +  +  +  +  :        4397 :         if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
             +  +  -  + ]
    1744                 :           5 :                 PG_RETURN_NULL();
    1745                 :             : 
    1746                 :             :         /* Sanity check: was the requested dim valid */
    1747   [ -  +  +  +  :        4392 :         if (reqdim <= 0 || reqdim > AARR_NDIM(v))
                   -  + ]
    1748                 :           0 :                 PG_RETURN_NULL();
    1749                 :             : 
    1750         [ +  + ]:        4392 :         lb = AARR_LBOUND(v);
    1751         [ +  + ]:        4392 :         dimv = AARR_DIMS(v);
    1752                 :             : 
    1753                 :        4392 :         result = dimv[reqdim - 1] + lb[reqdim - 1] - 1;
    1754                 :             : 
    1755                 :        4392 :         PG_RETURN_INT32(result);
    1756                 :        4397 : }
    1757                 :             : 
    1758                 :             : /*
    1759                 :             :  * array_length :
    1760                 :             :  *              returns the length, of the dimension requested, for
    1761                 :             :  *              the array pointed to by "v", as an int4
    1762                 :             :  */
    1763                 :             : Datum
    1764                 :       18734 : array_length(PG_FUNCTION_ARGS)
    1765                 :             : {
    1766                 :       18734 :         AnyArrayType *v = PG_GETARG_ANY_ARRAY_P(0);
    1767                 :       18734 :         int                     reqdim = PG_GETARG_INT32(1);
    1768                 :       18734 :         int                *dimv;
    1769                 :       18734 :         int                     result;
    1770                 :             : 
    1771                 :             :         /* Sanity check: does it look like an array at all? */
    1772   [ +  +  -  +  :       18734 :         if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
             +  +  -  + ]
    1773                 :           0 :                 PG_RETURN_NULL();
    1774                 :             : 
    1775                 :             :         /* Sanity check: was the requested dim valid */
    1776   [ +  +  +  +  :       18734 :         if (reqdim <= 0 || reqdim > AARR_NDIM(v))
                   +  + ]
    1777                 :           2 :                 PG_RETURN_NULL();
    1778                 :             : 
    1779         [ +  + ]:       18732 :         dimv = AARR_DIMS(v);
    1780                 :             : 
    1781                 :       18732 :         result = dimv[reqdim - 1];
    1782                 :             : 
    1783                 :       18732 :         PG_RETURN_INT32(result);
    1784                 :       18734 : }
    1785                 :             : 
    1786                 :             : /*
    1787                 :             :  * array_cardinality:
    1788                 :             :  *              returns the total number of elements in an array
    1789                 :             :  */
    1790                 :             : Datum
    1791                 :         422 : array_cardinality(PG_FUNCTION_ARGS)
    1792                 :             : {
    1793                 :         422 :         AnyArrayType *v = PG_GETARG_ANY_ARRAY_P(0);
    1794                 :             : 
    1795   [ +  -  +  - ]:         422 :         PG_RETURN_INT32(ArrayGetNItems(AARR_NDIM(v), AARR_DIMS(v)));
    1796                 :         422 : }
    1797                 :             : 
    1798                 :             : 
    1799                 :             : /*
    1800                 :             :  * array_get_element :
    1801                 :             :  *        This routine takes an array datum and a subscript array and returns
    1802                 :             :  *        the referenced item as a Datum.  Note that for a pass-by-reference
    1803                 :             :  *        datatype, the returned Datum is a pointer into the array object.
    1804                 :             :  *
    1805                 :             :  * This handles both ordinary varlena arrays and fixed-length arrays.
    1806                 :             :  *
    1807                 :             :  * Inputs:
    1808                 :             :  *      arraydatum: the array object (mustn't be NULL)
    1809                 :             :  *      nSubscripts: number of subscripts supplied
    1810                 :             :  *      indx[]: the subscript values
    1811                 :             :  *      arraytyplen: pg_type.typlen for the array type
    1812                 :             :  *      elmlen: pg_type.typlen for the array's element type
    1813                 :             :  *      elmbyval: pg_type.typbyval for the array's element type
    1814                 :             :  *      elmalign: pg_type.typalign for the array's element type
    1815                 :             :  *
    1816                 :             :  * Outputs:
    1817                 :             :  *      The return value is the element Datum.
    1818                 :             :  *      *isNull is set to indicate whether the element is NULL.
    1819                 :             :  */
    1820                 :             : Datum
    1821                 :       49121 : array_get_element(Datum arraydatum,
    1822                 :             :                                   int nSubscripts,
    1823                 :             :                                   int *indx,
    1824                 :             :                                   int arraytyplen,
    1825                 :             :                                   int elmlen,
    1826                 :             :                                   bool elmbyval,
    1827                 :             :                                   char elmalign,
    1828                 :             :                                   bool *isNull)
    1829                 :             : {
    1830                 :       49121 :         int                     i,
    1831                 :             :                                 ndim,
    1832                 :             :                            *dim,
    1833                 :             :                            *lb,
    1834                 :             :                                 offset,
    1835                 :             :                                 fixedDim[1],
    1836                 :             :                                 fixedLb[1];
    1837                 :       49121 :         char       *arraydataptr,
    1838                 :             :                            *retptr;
    1839                 :       49121 :         bits8      *arraynullsptr;
    1840                 :             : 
    1841         [ +  + ]:       49121 :         if (arraytyplen > 0)
    1842                 :             :         {
    1843                 :             :                 /*
    1844                 :             :                  * fixed-length arrays -- these are assumed to be 1-d, 0-based
    1845                 :             :                  */
    1846                 :         478 :                 ndim = 1;
    1847                 :         478 :                 fixedDim[0] = arraytyplen / elmlen;
    1848                 :         478 :                 fixedLb[0] = 0;
    1849                 :         478 :                 dim = fixedDim;
    1850                 :         478 :                 lb = fixedLb;
    1851                 :         478 :                 arraydataptr = (char *) DatumGetPointer(arraydatum);
    1852                 :         478 :                 arraynullsptr = NULL;
    1853                 :         478 :         }
    1854         [ +  + ]:       48643 :         else if (VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(arraydatum)))
    1855                 :             :         {
    1856                 :             :                 /* expanded array: let's do this in a separate function */
    1857                 :        1658 :                 return array_get_element_expanded(arraydatum,
    1858                 :         829 :                                                                                   nSubscripts,
    1859                 :         829 :                                                                                   indx,
    1860                 :         829 :                                                                                   arraytyplen,
    1861                 :         829 :                                                                                   elmlen,
    1862                 :         829 :                                                                                   elmbyval,
    1863                 :         829 :                                                                                   elmalign,
    1864                 :         829 :                                                                                   isNull);
    1865                 :             :         }
    1866                 :             :         else
    1867                 :             :         {
    1868                 :             :                 /* detoast array if necessary, producing normal varlena input */
    1869                 :       47814 :                 ArrayType  *array = DatumGetArrayTypeP(arraydatum);
    1870                 :             : 
    1871                 :       47814 :                 ndim = ARR_NDIM(array);
    1872                 :       47814 :                 dim = ARR_DIMS(array);
    1873                 :       47814 :                 lb = ARR_LBOUND(array);
    1874         [ +  + ]:       47814 :                 arraydataptr = ARR_DATA_PTR(array);
    1875         [ +  + ]:       47814 :                 arraynullsptr = ARR_NULLBITMAP(array);
    1876                 :       47814 :         }
    1877                 :             : 
    1878                 :             :         /*
    1879                 :             :          * Return NULL for invalid subscript
    1880                 :             :          */
    1881   [ +  +  +  -  :       48292 :         if (ndim != nSubscripts || ndim <= 0 || ndim > MAXDIM)
                   -  + ]
    1882                 :             :         {
    1883                 :          16 :                 *isNull = true;
    1884                 :          16 :                 return (Datum) 0;
    1885                 :             :         }
    1886         [ +  + ]:       87697 :         for (i = 0; i < ndim; i++)
    1887                 :             :         {
    1888   [ +  +  +  + ]:       48292 :                 if (indx[i] < lb[i] || indx[i] >= (dim[i] + lb[i]))
    1889                 :             :                 {
    1890                 :        8871 :                         *isNull = true;
    1891                 :        8871 :                         return (Datum) 0;
    1892                 :             :                 }
    1893                 :       39421 :         }
    1894                 :             : 
    1895                 :             :         /*
    1896                 :             :          * Calculate the element number
    1897                 :             :          */
    1898                 :       39405 :         offset = ArrayGetOffset(nSubscripts, dim, lb, indx);
    1899                 :             : 
    1900                 :             :         /*
    1901                 :             :          * Check for NULL array element
    1902                 :             :          */
    1903         [ +  + ]:       39405 :         if (array_get_isnull(arraynullsptr, offset))
    1904                 :             :         {
    1905                 :          12 :                 *isNull = true;
    1906                 :          12 :                 return (Datum) 0;
    1907                 :             :         }
    1908                 :             : 
    1909                 :             :         /*
    1910                 :             :          * OK, get the element
    1911                 :             :          */
    1912                 :       39393 :         *isNull = false;
    1913                 :       78786 :         retptr = array_seek(arraydataptr, 0, arraynullsptr, offset,
    1914                 :       39393 :                                                 elmlen, elmbyval, elmalign);
    1915                 :       39393 :         return ArrayCast(retptr, elmbyval, elmlen);
    1916                 :       49121 : }
    1917                 :             : 
    1918                 :             : /*
    1919                 :             :  * Implementation of array_get_element() for an expanded array
    1920                 :             :  */
    1921                 :             : static Datum
    1922                 :         829 : array_get_element_expanded(Datum arraydatum,
    1923                 :             :                                                    int nSubscripts, int *indx,
    1924                 :             :                                                    int arraytyplen,
    1925                 :             :                                                    int elmlen, bool elmbyval, char elmalign,
    1926                 :             :                                                    bool *isNull)
    1927                 :             : {
    1928                 :         829 :         ExpandedArrayHeader *eah;
    1929                 :         829 :         int                     i,
    1930                 :             :                                 ndim,
    1931                 :             :                            *dim,
    1932                 :             :                            *lb,
    1933                 :             :                                 offset;
    1934                 :         829 :         Datum      *dvalues;
    1935                 :         829 :         bool       *dnulls;
    1936                 :             : 
    1937                 :         829 :         eah = (ExpandedArrayHeader *) DatumGetEOHP(arraydatum);
    1938         [ +  - ]:         829 :         Assert(eah->ea_magic == EA_MAGIC);
    1939                 :             : 
    1940                 :             :         /* sanity-check caller's info against object */
    1941         [ +  - ]:         829 :         Assert(arraytyplen == -1);
    1942         [ +  - ]:         829 :         Assert(elmlen == eah->typlen);
    1943         [ +  - ]:         829 :         Assert(elmbyval == eah->typbyval);
    1944         [ +  - ]:         829 :         Assert(elmalign == eah->typalign);
    1945                 :             : 
    1946                 :         829 :         ndim = eah->ndims;
    1947                 :         829 :         dim = eah->dims;
    1948                 :         829 :         lb = eah->lbound;
    1949                 :             : 
    1950                 :             :         /*
    1951                 :             :          * Return NULL for invalid subscript
    1952                 :             :          */
    1953   [ +  +  +  -  :         829 :         if (ndim != nSubscripts || ndim <= 0 || ndim > MAXDIM)
                   -  + ]
    1954                 :             :         {
    1955                 :           1 :                 *isNull = true;
    1956                 :           1 :                 return (Datum) 0;
    1957                 :             :         }
    1958         [ +  + ]:        1656 :         for (i = 0; i < ndim; i++)
    1959                 :             :         {
    1960   [ +  -  -  + ]:         828 :                 if (indx[i] < lb[i] || indx[i] >= (dim[i] + lb[i]))
    1961                 :             :                 {
    1962                 :           0 :                         *isNull = true;
    1963                 :           0 :                         return (Datum) 0;
    1964                 :             :                 }
    1965                 :         828 :         }
    1966                 :             : 
    1967                 :             :         /*
    1968                 :             :          * Calculate the element number
    1969                 :             :          */
    1970                 :         828 :         offset = ArrayGetOffset(nSubscripts, dim, lb, indx);
    1971                 :             : 
    1972                 :             :         /*
    1973                 :             :          * Deconstruct array if we didn't already.  Note that we apply this even
    1974                 :             :          * if the input is nominally read-only: it should be safe enough.
    1975                 :             :          */
    1976                 :         828 :         deconstruct_expanded_array(eah);
    1977                 :             : 
    1978                 :         828 :         dvalues = eah->dvalues;
    1979                 :         828 :         dnulls = eah->dnulls;
    1980                 :             : 
    1981                 :             :         /*
    1982                 :             :          * Check for NULL array element
    1983                 :             :          */
    1984   [ -  +  #  # ]:         828 :         if (dnulls && dnulls[offset])
    1985                 :             :         {
    1986                 :           0 :                 *isNull = true;
    1987                 :           0 :                 return (Datum) 0;
    1988                 :             :         }
    1989                 :             : 
    1990                 :             :         /*
    1991                 :             :          * OK, get the element.  It's OK to return a pass-by-ref value as a
    1992                 :             :          * pointer into the expanded array, for the same reason that regular
    1993                 :             :          * array_get_element can return a pointer into flat arrays: the value is
    1994                 :             :          * assumed not to change for as long as the Datum reference can exist.
    1995                 :             :          */
    1996                 :         828 :         *isNull = false;
    1997                 :         828 :         return dvalues[offset];
    1998                 :         829 : }
    1999                 :             : 
    2000                 :             : /*
    2001                 :             :  * array_get_slice :
    2002                 :             :  *                 This routine takes an array and a range of indices (upperIndx and
    2003                 :             :  *                 lowerIndx), creates a new array structure for the referred elements
    2004                 :             :  *                 and returns a pointer to it.
    2005                 :             :  *
    2006                 :             :  * This handles both ordinary varlena arrays and fixed-length arrays.
    2007                 :             :  *
    2008                 :             :  * Inputs:
    2009                 :             :  *      arraydatum: the array object (mustn't be NULL)
    2010                 :             :  *      nSubscripts: number of subscripts supplied (must be same for upper/lower)
    2011                 :             :  *      upperIndx[]: the upper subscript values
    2012                 :             :  *      lowerIndx[]: the lower subscript values
    2013                 :             :  *      upperProvided[]: true for provided upper subscript values
    2014                 :             :  *      lowerProvided[]: true for provided lower subscript values
    2015                 :             :  *      arraytyplen: pg_type.typlen for the array type
    2016                 :             :  *      elmlen: pg_type.typlen for the array's element type
    2017                 :             :  *      elmbyval: pg_type.typbyval for the array's element type
    2018                 :             :  *      elmalign: pg_type.typalign for the array's element type
    2019                 :             :  *
    2020                 :             :  * Outputs:
    2021                 :             :  *      The return value is the new array Datum (it's never NULL)
    2022                 :             :  *
    2023                 :             :  * Omitted upper and lower subscript values are replaced by the corresponding
    2024                 :             :  * array bound.
    2025                 :             :  *
    2026                 :             :  * NOTE: we assume it is OK to scribble on the provided subscript arrays
    2027                 :             :  * lowerIndx[] and upperIndx[]; also, these arrays must be of size MAXDIM
    2028                 :             :  * even when nSubscripts is less.  These are generally just temporaries.
    2029                 :             :  */
    2030                 :             : Datum
    2031                 :          68 : array_get_slice(Datum arraydatum,
    2032                 :             :                                 int nSubscripts,
    2033                 :             :                                 int *upperIndx,
    2034                 :             :                                 int *lowerIndx,
    2035                 :             :                                 bool *upperProvided,
    2036                 :             :                                 bool *lowerProvided,
    2037                 :             :                                 int arraytyplen,
    2038                 :             :                                 int elmlen,
    2039                 :             :                                 bool elmbyval,
    2040                 :             :                                 char elmalign)
    2041                 :             : {
    2042                 :          68 :         ArrayType  *array;
    2043                 :          68 :         ArrayType  *newarray;
    2044                 :          68 :         int                     i,
    2045                 :             :                                 ndim,
    2046                 :             :                            *dim,
    2047                 :             :                            *lb,
    2048                 :             :                            *newlb;
    2049                 :          68 :         int                     fixedDim[1],
    2050                 :             :                                 fixedLb[1];
    2051                 :          68 :         Oid                     elemtype;
    2052                 :          68 :         char       *arraydataptr;
    2053                 :          68 :         bits8      *arraynullsptr;
    2054                 :          68 :         int32           dataoffset;
    2055                 :          68 :         int                     bytes,
    2056                 :             :                                 span[MAXDIM];
    2057                 :             : 
    2058         [ +  + ]:          68 :         if (arraytyplen > 0)
    2059                 :             :         {
    2060                 :             :                 /*
    2061                 :             :                  * fixed-length arrays -- currently, cannot slice these because parser
    2062                 :             :                  * labels output as being of the fixed-length array type! Code below
    2063                 :             :                  * shows how we could support it if the parser were changed to label
    2064                 :             :                  * output as a suitable varlena array type.
    2065                 :             :                  */
    2066   [ +  -  +  - ]:           4 :                 ereport(ERROR,
    2067                 :             :                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    2068                 :             :                                  errmsg("slices of fixed-length arrays not implemented")));
    2069                 :             : 
    2070                 :             :                 /*
    2071                 :             :                  * fixed-length arrays -- these are assumed to be 1-d, 0-based
    2072                 :             :                  *
    2073                 :             :                  * XXX where would we get the correct ELEMTYPE from?
    2074                 :             :                  */
    2075                 :           0 :                 ndim = 1;
    2076                 :           0 :                 fixedDim[0] = arraytyplen / elmlen;
    2077                 :           0 :                 fixedLb[0] = 0;
    2078                 :           0 :                 dim = fixedDim;
    2079                 :           0 :                 lb = fixedLb;
    2080                 :           0 :                 elemtype = InvalidOid;  /* XXX */
    2081                 :           0 :                 arraydataptr = (char *) DatumGetPointer(arraydatum);
    2082                 :           0 :                 arraynullsptr = NULL;
    2083                 :           0 :         }
    2084                 :             :         else
    2085                 :             :         {
    2086                 :             :                 /* detoast input array if necessary */
    2087                 :          64 :                 array = DatumGetArrayTypeP(arraydatum);
    2088                 :             : 
    2089                 :          64 :                 ndim = ARR_NDIM(array);
    2090                 :          64 :                 dim = ARR_DIMS(array);
    2091                 :          64 :                 lb = ARR_LBOUND(array);
    2092                 :          64 :                 elemtype = ARR_ELEMTYPE(array);
    2093         [ +  + ]:          64 :                 arraydataptr = ARR_DATA_PTR(array);
    2094         [ +  + ]:          64 :                 arraynullsptr = ARR_NULLBITMAP(array);
    2095                 :             :         }
    2096                 :             : 
    2097                 :             :         /*
    2098                 :             :          * Check provided subscripts.  A slice exceeding the current array limits
    2099                 :             :          * is silently truncated to the array limits.  If we end up with an empty
    2100                 :             :          * slice, return an empty array.
    2101                 :             :          */
    2102   [ +  +  +  -  :          64 :         if (ndim < nSubscripts || ndim <= 0 || ndim > MAXDIM)
                   -  + ]
    2103                 :          16 :                 return PointerGetDatum(construct_empty_array(elemtype));
    2104                 :             : 
    2105         [ +  + ]:         110 :         for (i = 0; i < nSubscripts; i++)
    2106                 :             :         {
    2107   [ +  +  +  + ]:          64 :                 if (!lowerProvided[i] || lowerIndx[i] < lb[i])
    2108                 :          21 :                         lowerIndx[i] = lb[i];
    2109   [ +  +  +  + ]:          64 :                 if (!upperProvided[i] || upperIndx[i] >= (dim[i] + lb[i]))
    2110                 :          12 :                         upperIndx[i] = dim[i] + lb[i] - 1;
    2111         [ +  + ]:          64 :                 if (lowerIndx[i] > upperIndx[i])
    2112                 :           2 :                         return PointerGetDatum(construct_empty_array(elemtype));
    2113                 :          62 :         }
    2114                 :             :         /* fill any missing subscript positions with full array range */
    2115         [ +  + ]:          54 :         for (; i < ndim; i++)
    2116                 :             :         {
    2117                 :           8 :                 lowerIndx[i] = lb[i];
    2118                 :           8 :                 upperIndx[i] = dim[i] + lb[i] - 1;
    2119         [ -  + ]:           8 :                 if (lowerIndx[i] > upperIndx[i])
    2120                 :           0 :                         return PointerGetDatum(construct_empty_array(elemtype));
    2121                 :           8 :         }
    2122                 :             : 
    2123                 :          46 :         mda_get_range(ndim, span, lowerIndx, upperIndx);
    2124                 :             : 
    2125                 :          92 :         bytes = array_slice_size(arraydataptr, arraynullsptr,
    2126                 :          46 :                                                          ndim, dim, lb,
    2127                 :          46 :                                                          lowerIndx, upperIndx,
    2128                 :          46 :                                                          elmlen, elmbyval, elmalign);
    2129                 :             : 
    2130                 :             :         /*
    2131                 :             :          * Currently, we put a null bitmap in the result if the source has one;
    2132                 :             :          * could be smarter ...
    2133                 :             :          */
    2134         [ +  + ]:          46 :         if (arraynullsptr)
    2135                 :             :         {
    2136                 :           6 :                 dataoffset = ARR_OVERHEAD_WITHNULLS(ndim, ArrayGetNItems(ndim, span));
    2137                 :           6 :                 bytes += dataoffset;
    2138                 :           6 :         }
    2139                 :             :         else
    2140                 :             :         {
    2141                 :          40 :                 dataoffset = 0;                 /* marker for no null bitmap */
    2142                 :          40 :                 bytes += ARR_OVERHEAD_NONULLS(ndim);
    2143                 :             :         }
    2144                 :             : 
    2145                 :          46 :         newarray = (ArrayType *) palloc0(bytes);
    2146                 :          46 :         SET_VARSIZE(newarray, bytes);
    2147                 :          46 :         newarray->ndim = ndim;
    2148                 :          46 :         newarray->dataoffset = dataoffset;
    2149                 :          46 :         newarray->elemtype = elemtype;
    2150                 :          46 :         memcpy(ARR_DIMS(newarray), span, ndim * sizeof(int));
    2151                 :             : 
    2152                 :             :         /*
    2153                 :             :          * Lower bounds of the new array are set to 1.  Formerly (before 7.3) we
    2154                 :             :          * copied the given lowerIndx values ... but that seems confusing.
    2155                 :             :          */
    2156                 :          46 :         newlb = ARR_LBOUND(newarray);
    2157         [ +  + ]:         116 :         for (i = 0; i < ndim; i++)
    2158                 :          70 :                 newlb[i] = 1;
    2159                 :             : 
    2160                 :          92 :         array_extract_slice(newarray,
    2161                 :          46 :                                                 ndim, dim, lb,
    2162                 :          46 :                                                 arraydataptr, arraynullsptr,
    2163                 :          46 :                                                 lowerIndx, upperIndx,
    2164                 :          46 :                                                 elmlen, elmbyval, elmalign);
    2165                 :             : 
    2166                 :          46 :         return PointerGetDatum(newarray);
    2167                 :          64 : }
    2168                 :             : 
    2169                 :             : /*
    2170                 :             :  * array_set_element :
    2171                 :             :  *                This routine sets the value of one array element (specified by
    2172                 :             :  *                a subscript array) to a new value specified by "dataValue".
    2173                 :             :  *
    2174                 :             :  * This handles both ordinary varlena arrays and fixed-length arrays.
    2175                 :             :  *
    2176                 :             :  * Inputs:
    2177                 :             :  *      arraydatum: the initial array object (mustn't be NULL)
    2178                 :             :  *      nSubscripts: number of subscripts supplied
    2179                 :             :  *      indx[]: the subscript values
    2180                 :             :  *      dataValue: the datum to be inserted at the given position
    2181                 :             :  *      isNull: whether dataValue is NULL
    2182                 :             :  *      arraytyplen: pg_type.typlen for the array type
    2183                 :             :  *      elmlen: pg_type.typlen for the array's element type
    2184                 :             :  *      elmbyval: pg_type.typbyval for the array's element type
    2185                 :             :  *      elmalign: pg_type.typalign for the array's element type
    2186                 :             :  *
    2187                 :             :  * Result:
    2188                 :             :  *                A new array is returned, just like the old except for the one
    2189                 :             :  *                modified entry.  The original array object is not changed,
    2190                 :             :  *                unless what is passed is a read-write reference to an expanded
    2191                 :             :  *                array object; in that case the expanded array is updated in-place.
    2192                 :             :  *
    2193                 :             :  * For one-dimensional arrays only, we allow the array to be extended
    2194                 :             :  * by assigning to a position outside the existing subscript range; any
    2195                 :             :  * positions between the existing elements and the new one are set to NULLs.
    2196                 :             :  * (XXX TODO: allow a corresponding behavior for multidimensional arrays)
    2197                 :             :  *
    2198                 :             :  * NOTE: For assignments, we throw an error for invalid subscripts etc,
    2199                 :             :  * rather than returning a NULL as the fetch operations do.
    2200                 :             :  */
    2201                 :             : Datum
    2202                 :         491 : array_set_element(Datum arraydatum,
    2203                 :             :                                   int nSubscripts,
    2204                 :             :                                   int *indx,
    2205                 :             :                                   Datum dataValue,
    2206                 :             :                                   bool isNull,
    2207                 :             :                                   int arraytyplen,
    2208                 :             :                                   int elmlen,
    2209                 :             :                                   bool elmbyval,
    2210                 :             :                                   char elmalign)
    2211                 :             : {
    2212                 :         491 :         ArrayType  *array;
    2213                 :         491 :         ArrayType  *newarray;
    2214                 :         491 :         int                     i,
    2215                 :             :                                 ndim,
    2216                 :             :                                 dim[MAXDIM],
    2217                 :             :                                 lb[MAXDIM],
    2218                 :             :                                 offset;
    2219                 :         491 :         char       *elt_ptr;
    2220                 :         491 :         bool            newhasnulls;
    2221                 :         491 :         bits8      *oldnullbitmap;
    2222                 :         491 :         int                     oldnitems,
    2223                 :             :                                 newnitems,
    2224                 :             :                                 olddatasize,
    2225                 :             :                                 newsize,
    2226                 :             :                                 olditemlen,
    2227                 :             :                                 newitemlen,
    2228                 :             :                                 overheadlen,
    2229                 :             :                                 oldoverheadlen,
    2230                 :             :                                 addedbefore,
    2231                 :             :                                 addedafter,
    2232                 :             :                                 lenbefore,
    2233                 :             :                                 lenafter;
    2234                 :             : 
    2235         [ +  + ]:         491 :         if (arraytyplen > 0)
    2236                 :             :         {
    2237                 :             :                 /*
    2238                 :             :                  * fixed-length arrays -- these are assumed to be 1-d, 0-based. We
    2239                 :             :                  * cannot extend them, either.
    2240                 :             :                  */
    2241                 :           3 :                 char       *resultarray;
    2242                 :             : 
    2243         [ +  - ]:           3 :                 if (nSubscripts != 1)
    2244   [ #  #  #  # ]:           0 :                         ereport(ERROR,
    2245                 :             :                                         (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    2246                 :             :                                          errmsg("wrong number of array subscripts")));
    2247                 :             : 
    2248         [ +  + ]:           3 :                 if (indx[0] < 0 || indx[0] >= arraytyplen / elmlen)
    2249   [ +  -  +  - ]:           1 :                         ereport(ERROR,
    2250                 :             :                                         (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    2251                 :             :                                          errmsg("array subscript out of range")));
    2252                 :             : 
    2253         [ +  - ]:           2 :                 if (isNull)
    2254   [ #  #  #  # ]:           0 :                         ereport(ERROR,
    2255                 :             :                                         (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    2256                 :             :                                          errmsg("cannot assign null value to an element of a fixed-length array")));
    2257                 :             : 
    2258                 :           2 :                 resultarray = (char *) palloc(arraytyplen);
    2259                 :           2 :                 memcpy(resultarray, DatumGetPointer(arraydatum), arraytyplen);
    2260                 :           2 :                 elt_ptr = resultarray + indx[0] * elmlen;
    2261                 :           2 :                 ArrayCastAndSet(dataValue, elmlen, elmbyval, elmalign, elt_ptr);
    2262                 :           2 :                 return PointerGetDatum(resultarray);
    2263                 :           2 :         }
    2264                 :             : 
    2265         [ +  - ]:         488 :         if (nSubscripts <= 0 || nSubscripts > MAXDIM)
    2266   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    2267                 :             :                                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    2268                 :             :                                  errmsg("wrong number of array subscripts")));
    2269                 :             : 
    2270                 :             :         /* make sure item to be inserted is not toasted */
    2271   [ +  +  -  + ]:         488 :         if (elmlen == -1 && !isNull)
    2272                 :         237 :                 dataValue = PointerGetDatum(PG_DETOAST_DATUM(dataValue));
    2273                 :             : 
    2274         [ +  + ]:         488 :         if (VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(arraydatum)))
    2275                 :             :         {
    2276                 :             :                 /* expanded array: let's do this in a separate function */
    2277                 :         620 :                 return array_set_element_expanded(arraydatum,
    2278                 :         310 :                                                                                   nSubscripts,
    2279                 :         310 :                                                                                   indx,
    2280                 :         310 :                                                                                   dataValue,
    2281                 :         310 :                                                                                   isNull,
    2282                 :         310 :                                                                                   arraytyplen,
    2283                 :         310 :                                                                                   elmlen,
    2284                 :         310 :                                                                                   elmbyval,
    2285                 :         310 :                                                                                   elmalign);
    2286                 :             :         }
    2287                 :             : 
    2288                 :             :         /* detoast input array if necessary */
    2289                 :         178 :         array = DatumGetArrayTypeP(arraydatum);
    2290                 :             : 
    2291                 :         178 :         ndim = ARR_NDIM(array);
    2292                 :             : 
    2293                 :             :         /*
    2294                 :             :          * if number of dims is zero, i.e. an empty array, create an array with
    2295                 :             :          * nSubscripts dimensions, and set the lower bounds to the supplied
    2296                 :             :          * subscripts
    2297                 :             :          */
    2298         [ +  + ]:         178 :         if (ndim == 0)
    2299                 :             :         {
    2300                 :          56 :                 Oid                     elmtype = ARR_ELEMTYPE(array);
    2301                 :             : 
    2302         [ +  + ]:         112 :                 for (i = 0; i < nSubscripts; i++)
    2303                 :             :                 {
    2304                 :          56 :                         dim[i] = 1;
    2305                 :          56 :                         lb[i] = indx[i];
    2306                 :          56 :                 }
    2307                 :             : 
    2308                 :          56 :                 return PointerGetDatum(construct_md_array(&dataValue, &isNull,
    2309                 :          56 :                                                                                                   nSubscripts, dim, lb,
    2310                 :          56 :                                                                                                   elmtype,
    2311                 :          56 :                                                                                                   elmlen, elmbyval, elmalign));
    2312                 :          56 :         }
    2313                 :             : 
    2314         [ +  + ]:         122 :         if (ndim != nSubscripts)
    2315   [ +  -  +  - ]:           1 :                 ereport(ERROR,
    2316                 :             :                                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    2317                 :             :                                  errmsg("wrong number of array subscripts")));
    2318                 :             : 
    2319                 :             :         /* copy dim/lb since we may modify them */
    2320                 :         121 :         memcpy(dim, ARR_DIMS(array), ndim * sizeof(int));
    2321                 :         121 :         memcpy(lb, ARR_LBOUND(array), ndim * sizeof(int));
    2322                 :             : 
    2323         [ +  + ]:         121 :         newhasnulls = (ARR_HASNULL(array) || isNull);
    2324                 :         121 :         addedbefore = addedafter = 0;
    2325                 :             : 
    2326                 :             :         /*
    2327                 :             :          * Check subscripts.  We assume the existing subscripts passed
    2328                 :             :          * ArrayCheckBounds, so that dim[i] + lb[i] can be computed without
    2329                 :             :          * overflow.  But we must beware of other overflows in our calculations of
    2330                 :             :          * new dim[] values.
    2331                 :             :          */
    2332         [ +  + ]:         121 :         if (ndim == 1)
    2333                 :             :         {
    2334         [ +  + ]:         120 :                 if (indx[0] < lb[0])
    2335                 :             :                 {
    2336                 :             :                         /* addedbefore = lb[0] - indx[0]; */
    2337                 :             :                         /* dim[0] += addedbefore; */
    2338         [ +  - ]:           4 :                         if (pg_sub_s32_overflow(lb[0], indx[0], &addedbefore) ||
    2339                 :           4 :                                 pg_add_s32_overflow(dim[0], addedbefore, &dim[0]))
    2340   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
    2341                 :             :                                                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    2342                 :             :                                                  errmsg("array size exceeds the maximum allowed (%zu)",
    2343                 :             :                                                                 MaxArraySize)));
    2344                 :           4 :                         lb[0] = indx[0];
    2345         [ +  + ]:           4 :                         if (addedbefore > 1)
    2346                 :           2 :                                 newhasnulls = true; /* will insert nulls */
    2347                 :           4 :                 }
    2348         [ +  + ]:         120 :                 if (indx[0] >= (dim[0] + lb[0]))
    2349                 :             :                 {
    2350                 :             :                         /* addedafter = indx[0] - (dim[0] + lb[0]) + 1; */
    2351                 :             :                         /* dim[0] += addedafter; */
    2352         [ +  + ]:          62 :                         if (pg_sub_s32_overflow(indx[0], dim[0] + lb[0], &addedafter) ||
    2353                 :          61 :                                 pg_add_s32_overflow(addedafter, 1, &addedafter) ||
    2354                 :          61 :                                 pg_add_s32_overflow(dim[0], addedafter, &dim[0]))
    2355   [ +  -  +  - ]:           1 :                                 ereport(ERROR,
    2356                 :             :                                                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    2357                 :             :                                                  errmsg("array size exceeds the maximum allowed (%zu)",
    2358                 :             :                                                                 MaxArraySize)));
    2359         [ +  + ]:          61 :                         if (addedafter > 1)
    2360                 :           6 :                                 newhasnulls = true; /* will insert nulls */
    2361                 :          61 :                 }
    2362                 :         119 :         }
    2363                 :             :         else
    2364                 :             :         {
    2365                 :             :                 /*
    2366                 :             :                  * XXX currently we do not support extending multi-dimensional arrays
    2367                 :             :                  * during assignment
    2368                 :             :                  */
    2369         [ +  + ]:           3 :                 for (i = 0; i < ndim; i++)
    2370                 :             :                 {
    2371         [ +  - ]:           2 :                         if (indx[i] < lb[i] ||
    2372                 :           2 :                                 indx[i] >= (dim[i] + lb[i]))
    2373   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
    2374                 :             :                                                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    2375                 :             :                                                  errmsg("array subscript out of range")));
    2376                 :           2 :                 }
    2377                 :             :         }
    2378                 :             : 
    2379                 :             :         /* This checks for overflow of the array dimensions */
    2380                 :         120 :         newnitems = ArrayGetNItems(ndim, dim);
    2381                 :         120 :         ArrayCheckBounds(ndim, dim, lb);
    2382                 :             : 
    2383                 :             :         /*
    2384                 :             :          * Compute sizes of items and areas to copy
    2385                 :             :          */
    2386         [ +  + ]:         120 :         if (newhasnulls)
    2387                 :          22 :                 overheadlen = ARR_OVERHEAD_WITHNULLS(ndim, newnitems);
    2388                 :             :         else
    2389                 :          98 :                 overheadlen = ARR_OVERHEAD_NONULLS(ndim);
    2390                 :         120 :         oldnitems = ArrayGetNItems(ndim, ARR_DIMS(array));
    2391         [ +  + ]:         120 :         oldnullbitmap = ARR_NULLBITMAP(array);
    2392         [ +  + ]:         120 :         oldoverheadlen = ARR_DATA_OFFSET(array);
    2393                 :         120 :         olddatasize = ARR_SIZE(array) - oldoverheadlen;
    2394         [ +  + ]:         120 :         if (addedbefore)
    2395                 :             :         {
    2396                 :           4 :                 offset = 0;
    2397                 :           4 :                 lenbefore = 0;
    2398                 :           4 :                 olditemlen = 0;
    2399                 :           4 :                 lenafter = olddatasize;
    2400                 :           4 :         }
    2401         [ +  + ]:         116 :         else if (addedafter)
    2402                 :             :         {
    2403                 :          61 :                 offset = oldnitems;
    2404                 :          61 :                 lenbefore = olddatasize;
    2405                 :          61 :                 olditemlen = 0;
    2406                 :          61 :                 lenafter = 0;
    2407                 :          61 :         }
    2408                 :             :         else
    2409                 :             :         {
    2410                 :          55 :                 offset = ArrayGetOffset(nSubscripts, dim, lb, indx);
    2411         [ +  + ]:          55 :                 elt_ptr = array_seek(ARR_DATA_PTR(array), 0, oldnullbitmap, offset,
    2412                 :          55 :                                                          elmlen, elmbyval, elmalign);
    2413         [ +  + ]:          55 :                 lenbefore = (int) (elt_ptr - ARR_DATA_PTR(array));
    2414         [ +  + ]:          55 :                 if (array_get_isnull(oldnullbitmap, offset))
    2415                 :           4 :                         olditemlen = 0;
    2416                 :             :                 else
    2417                 :             :                 {
    2418   [ +  +  -  +  :          51 :                         olditemlen = att_addlength_pointer(0, elmlen, elt_ptr);
                   #  # ]
    2419   [ +  +  -  +  :          51 :                         olditemlen = att_align_nominal(olditemlen, elmalign);
             +  -  #  # ]
    2420                 :             :                 }
    2421                 :          55 :                 lenafter = olddatasize - lenbefore - olditemlen;
    2422                 :             :         }
    2423                 :             : 
    2424         [ +  + ]:         120 :         if (isNull)
    2425                 :           3 :                 newitemlen = 0;
    2426                 :             :         else
    2427                 :             :         {
    2428   [ +  +  -  +  :         117 :                 newitemlen = att_addlength_datum(0, elmlen, dataValue);
                   #  # ]
    2429   [ +  +  -  +  :         117 :                 newitemlen = att_align_nominal(newitemlen, elmalign);
             +  -  #  # ]
    2430                 :             :         }
    2431                 :             : 
    2432                 :         120 :         newsize = overheadlen + lenbefore + newitemlen + lenafter;
    2433                 :             : 
    2434                 :             :         /*
    2435                 :             :          * OK, create the new array and fill in header/dimensions
    2436                 :             :          */
    2437                 :         120 :         newarray = (ArrayType *) palloc0(newsize);
    2438                 :         120 :         SET_VARSIZE(newarray, newsize);
    2439                 :         120 :         newarray->ndim = ndim;
    2440         [ +  + ]:         120 :         newarray->dataoffset = newhasnulls ? overheadlen : 0;
    2441                 :         120 :         newarray->elemtype = ARR_ELEMTYPE(array);
    2442                 :         120 :         memcpy(ARR_DIMS(newarray), dim, ndim * sizeof(int));
    2443                 :         120 :         memcpy(ARR_LBOUND(newarray), lb, ndim * sizeof(int));
    2444                 :             : 
    2445                 :             :         /*
    2446                 :             :          * Fill in data
    2447                 :             :          */
    2448                 :         120 :         memcpy((char *) newarray + overheadlen,
    2449                 :             :                    (char *) array + oldoverheadlen,
    2450                 :             :                    lenbefore);
    2451         [ +  + ]:         120 :         if (!isNull)
    2452                 :         234 :                 ArrayCastAndSet(dataValue, elmlen, elmbyval, elmalign,
    2453                 :         117 :                                                 (char *) newarray + overheadlen + lenbefore);
    2454                 :         120 :         memcpy((char *) newarray + overheadlen + lenbefore + newitemlen,
    2455                 :             :                    (char *) array + oldoverheadlen + lenbefore + olditemlen,
    2456                 :             :                    lenafter);
    2457                 :             : 
    2458                 :             :         /*
    2459                 :             :          * Fill in nulls bitmap if needed
    2460                 :             :          *
    2461                 :             :          * Note: it's possible we just replaced the last NULL with a non-NULL, and
    2462                 :             :          * could get rid of the bitmap.  Seems not worth testing for though.
    2463                 :             :          */
    2464         [ +  + ]:         120 :         if (newhasnulls)
    2465                 :             :         {
    2466         [ +  - ]:          22 :                 bits8      *newnullbitmap = ARR_NULLBITMAP(newarray);
    2467                 :             : 
    2468                 :             :                 /* palloc0 above already marked any inserted positions as nulls */
    2469                 :             :                 /* Fix the inserted value */
    2470         [ +  + ]:          22 :                 if (addedafter)
    2471                 :           9 :                         array_set_isnull(newnullbitmap, newnitems - 1, isNull);
    2472                 :             :                 else
    2473                 :          13 :                         array_set_isnull(newnullbitmap, offset, isNull);
    2474                 :             :                 /* Fix the copied range(s) */
    2475         [ +  + ]:          22 :                 if (addedbefore)
    2476                 :           8 :                         array_bitmap_copy(newnullbitmap, addedbefore,
    2477                 :           4 :                                                           oldnullbitmap, 0,
    2478                 :           4 :                                                           oldnitems);
    2479                 :             :                 else
    2480                 :             :                 {
    2481                 :          36 :                         array_bitmap_copy(newnullbitmap, 0,
    2482                 :          18 :                                                           oldnullbitmap, 0,
    2483                 :          18 :                                                           offset);
    2484         [ +  + ]:          18 :                         if (addedafter == 0)
    2485                 :          18 :                                 array_bitmap_copy(newnullbitmap, offset + 1,
    2486                 :           9 :                                                                   oldnullbitmap, offset + 1,
    2487                 :           9 :                                                                   oldnitems - offset - 1);
    2488                 :             :                 }
    2489                 :          22 :         }
    2490                 :             : 
    2491                 :         120 :         return PointerGetDatum(newarray);
    2492                 :         488 : }
    2493                 :             : 
    2494                 :             : /*
    2495                 :             :  * Implementation of array_set_element() for an expanded array
    2496                 :             :  *
    2497                 :             :  * Note: as with any operation on a read/write expanded object, we must
    2498                 :             :  * take pains not to leave the object in a corrupt state if we fail partway
    2499                 :             :  * through.
    2500                 :             :  */
    2501                 :             : static Datum
    2502                 :         310 : array_set_element_expanded(Datum arraydatum,
    2503                 :             :                                                    int nSubscripts, int *indx,
    2504                 :             :                                                    Datum dataValue, bool isNull,
    2505                 :             :                                                    int arraytyplen,
    2506                 :             :                                                    int elmlen, bool elmbyval, char elmalign)
    2507                 :             : {
    2508                 :         310 :         ExpandedArrayHeader *eah;
    2509                 :         310 :         Datum      *dvalues;
    2510                 :         310 :         bool       *dnulls;
    2511                 :         310 :         int                     i,
    2512                 :             :                                 ndim,
    2513                 :             :                                 dim[MAXDIM],
    2514                 :             :                                 lb[MAXDIM],
    2515                 :             :                                 offset;
    2516                 :         310 :         bool            dimschanged,
    2517                 :             :                                 newhasnulls;
    2518                 :         310 :         int                     addedbefore,
    2519                 :             :                                 addedafter;
    2520                 :         310 :         char       *oldValue;
    2521                 :             : 
    2522                 :             :         /* Convert to R/W object if not so already */
    2523                 :         310 :         eah = DatumGetExpandedArray(arraydatum);
    2524                 :             : 
    2525                 :             :         /* Sanity-check caller's info against object; we don't use it otherwise */
    2526         [ +  - ]:         310 :         Assert(arraytyplen == -1);
    2527         [ +  - ]:         310 :         Assert(elmlen == eah->typlen);
    2528         [ +  - ]:         310 :         Assert(elmbyval == eah->typbyval);
    2529         [ +  - ]:         310 :         Assert(elmalign == eah->typalign);
    2530                 :             : 
    2531                 :             :         /*
    2532                 :             :          * Copy dimension info into local storage.  This allows us to modify the
    2533                 :             :          * dimensions if needed, while not messing up the expanded value if we
    2534                 :             :          * fail partway through.
    2535                 :             :          */
    2536                 :         310 :         ndim = eah->ndims;
    2537         [ +  - ]:         310 :         Assert(ndim >= 0 && ndim <= MAXDIM);
    2538                 :         310 :         memcpy(dim, eah->dims, ndim * sizeof(int));
    2539                 :         310 :         memcpy(lb, eah->lbound, ndim * sizeof(int));
    2540                 :         310 :         dimschanged = false;
    2541                 :             : 
    2542                 :             :         /*
    2543                 :             :          * if number of dims is zero, i.e. an empty array, create an array with
    2544                 :             :          * nSubscripts dimensions, and set the lower bounds to the supplied
    2545                 :             :          * subscripts.
    2546                 :             :          */
    2547         [ +  + ]:         310 :         if (ndim == 0)
    2548                 :             :         {
    2549                 :             :                 /*
    2550                 :             :                  * Allocate adequate space for new dimension info.  This is harmless
    2551                 :             :                  * if we fail later.
    2552                 :             :                  */
    2553         [ +  - ]:          52 :                 Assert(nSubscripts > 0 && nSubscripts <= MAXDIM);
    2554                 :         104 :                 eah->dims = (int *) MemoryContextAllocZero(eah->hdr.eoh_context,
    2555                 :          52 :                                                                                                    nSubscripts * sizeof(int));
    2556                 :         104 :                 eah->lbound = (int *) MemoryContextAllocZero(eah->hdr.eoh_context,
    2557                 :          52 :                                                                                                          nSubscripts * sizeof(int));
    2558                 :             : 
    2559                 :             :                 /* Update local copies of dimension info */
    2560                 :          52 :                 ndim = nSubscripts;
    2561         [ +  + ]:         104 :                 for (i = 0; i < nSubscripts; i++)
    2562                 :             :                 {
    2563                 :          52 :                         dim[i] = 0;
    2564                 :          52 :                         lb[i] = indx[i];
    2565                 :          52 :                 }
    2566                 :          52 :                 dimschanged = true;
    2567                 :          52 :         }
    2568         [ +  - ]:         258 :         else if (ndim != nSubscripts)
    2569   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    2570                 :             :                                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    2571                 :             :                                  errmsg("wrong number of array subscripts")));
    2572                 :             : 
    2573                 :             :         /*
    2574                 :             :          * Deconstruct array if we didn't already.  (Someday maybe add a special
    2575                 :             :          * case path for fixed-length, no-nulls cases, where we can overwrite an
    2576                 :             :          * element in place without ever deconstructing.  But today is not that
    2577                 :             :          * day.)
    2578                 :             :          */
    2579                 :         310 :         deconstruct_expanded_array(eah);
    2580                 :             : 
    2581                 :             :         /*
    2582                 :             :          * Copy new element into array's context, if needed (we assume it's
    2583                 :             :          * already detoasted, so no junk should be created).  Doing this before
    2584                 :             :          * we've made any significant changes ensures that our behavior is sane
    2585                 :             :          * even when the source is a reference to some element of this same array.
    2586                 :             :          * If we fail further down, this memory is leaked, but that's reasonably
    2587                 :             :          * harmless.
    2588                 :             :          */
    2589   [ +  +  -  + ]:         310 :         if (!eah->typbyval && !isNull)
    2590                 :             :         {
    2591                 :         126 :                 MemoryContext oldcxt = MemoryContextSwitchTo(eah->hdr.eoh_context);
    2592                 :             : 
    2593                 :         126 :                 dataValue = datumCopy(dataValue, false, eah->typlen);
    2594                 :         126 :                 MemoryContextSwitchTo(oldcxt);
    2595                 :         126 :         }
    2596                 :             : 
    2597                 :         310 :         dvalues = eah->dvalues;
    2598                 :         310 :         dnulls = eah->dnulls;
    2599                 :             : 
    2600         [ -  + ]:         310 :         newhasnulls = ((dnulls != NULL) || isNull);
    2601                 :         310 :         addedbefore = addedafter = 0;
    2602                 :             : 
    2603                 :             :         /*
    2604                 :             :          * Check subscripts (this logic must match array_set_element).  We assume
    2605                 :             :          * the existing subscripts passed ArrayCheckBounds, so that dim[i] + lb[i]
    2606                 :             :          * can be computed without overflow.  But we must beware of other
    2607                 :             :          * overflows in our calculations of new dim[] values.
    2608                 :             :          */
    2609         [ +  - ]:         310 :         if (ndim == 1)
    2610                 :             :         {
    2611         [ +  + ]:         310 :                 if (indx[0] < lb[0])
    2612                 :             :                 {
    2613                 :             :                         /* addedbefore = lb[0] - indx[0]; */
    2614                 :             :                         /* dim[0] += addedbefore; */
    2615         [ +  - ]:          13 :                         if (pg_sub_s32_overflow(lb[0], indx[0], &addedbefore) ||
    2616                 :          13 :                                 pg_add_s32_overflow(dim[0], addedbefore, &dim[0]))
    2617   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
    2618                 :             :                                                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    2619                 :             :                                                  errmsg("array size exceeds the maximum allowed (%zu)",
    2620                 :             :                                                                 MaxArraySize)));
    2621                 :          13 :                         lb[0] = indx[0];
    2622                 :          13 :                         dimschanged = true;
    2623         [ +  - ]:          13 :                         if (addedbefore > 1)
    2624                 :           0 :                                 newhasnulls = true; /* will insert nulls */
    2625                 :          13 :                 }
    2626         [ +  + ]:         310 :                 if (indx[0] >= (dim[0] + lb[0]))
    2627                 :             :                 {
    2628                 :             :                         /* addedafter = indx[0] - (dim[0] + lb[0]) + 1; */
    2629                 :             :                         /* dim[0] += addedafter; */
    2630         [ +  + ]:         290 :                         if (pg_sub_s32_overflow(indx[0], dim[0] + lb[0], &addedafter) ||
    2631                 :         289 :                                 pg_add_s32_overflow(addedafter, 1, &addedafter) ||
    2632                 :         289 :                                 pg_add_s32_overflow(dim[0], addedafter, &dim[0]))
    2633   [ +  -  +  - ]:           1 :                                 ereport(ERROR,
    2634                 :             :                                                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    2635                 :             :                                                  errmsg("array size exceeds the maximum allowed (%zu)",
    2636                 :             :                                                                 MaxArraySize)));
    2637                 :         289 :                         dimschanged = true;
    2638         [ +  - ]:         289 :                         if (addedafter > 1)
    2639                 :           0 :                                 newhasnulls = true; /* will insert nulls */
    2640                 :         289 :                 }
    2641                 :         309 :         }
    2642                 :             :         else
    2643                 :             :         {
    2644                 :             :                 /*
    2645                 :             :                  * XXX currently we do not support extending multi-dimensional arrays
    2646                 :             :                  * during assignment
    2647                 :             :                  */
    2648         [ #  # ]:           0 :                 for (i = 0; i < ndim; i++)
    2649                 :             :                 {
    2650         [ #  # ]:           0 :                         if (indx[i] < lb[i] ||
    2651                 :           0 :                                 indx[i] >= (dim[i] + lb[i]))
    2652   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
    2653                 :             :                                                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    2654                 :             :                                                  errmsg("array subscript out of range")));
    2655                 :           0 :                 }
    2656                 :             :         }
    2657                 :             : 
    2658                 :             :         /* Check for overflow of the array dimensions */
    2659         [ +  + ]:         309 :         if (dimschanged)
    2660                 :             :         {
    2661                 :         302 :                 (void) ArrayGetNItems(ndim, dim);
    2662                 :         302 :                 ArrayCheckBounds(ndim, dim, lb);
    2663                 :         302 :         }
    2664                 :             : 
    2665                 :             :         /* Now we can calculate linear offset of target item in array */
    2666                 :         309 :         offset = ArrayGetOffset(nSubscripts, dim, lb, indx);
    2667                 :             : 
    2668                 :             :         /* Physically enlarge existing dvalues/dnulls arrays if needed */
    2669         [ +  + ]:         309 :         if (dim[0] > eah->dvalueslen)
    2670                 :             :         {
    2671                 :             :                 /* We want some extra space if we're enlarging */
    2672                 :         300 :                 int                     newlen = dim[0] + dim[0] / 8;
    2673                 :             : 
    2674         [ +  + ]:         300 :                 newlen = Max(newlen, dim[0]);   /* integer overflow guard */
    2675                 :         300 :                 eah->dvalues = dvalues = (Datum *)
    2676                 :         300 :                         repalloc(dvalues, newlen * sizeof(Datum));
    2677         [ -  + ]:         300 :                 if (dnulls)
    2678                 :           0 :                         eah->dnulls = dnulls = (bool *)
    2679                 :           0 :                                 repalloc(dnulls, newlen * sizeof(bool));
    2680                 :         300 :                 eah->dvalueslen = newlen;
    2681                 :         300 :         }
    2682                 :             : 
    2683                 :             :         /*
    2684                 :             :          * If we need a nulls bitmap and don't already have one, create it, being
    2685                 :             :          * sure to mark all existing entries as not null.
    2686                 :             :          */
    2687   [ -  +  #  # ]:         309 :         if (newhasnulls && dnulls == NULL)
    2688                 :           0 :                 eah->dnulls = dnulls = (bool *)
    2689                 :           0 :                         MemoryContextAllocZero(eah->hdr.eoh_context,
    2690                 :           0 :                                                                    eah->dvalueslen * sizeof(bool));
    2691                 :             : 
    2692                 :             :         /*
    2693                 :             :          * We now have all the needed space allocated, so we're ready to make
    2694                 :             :          * irreversible changes.  Be very wary of allowing failure below here.
    2695                 :             :          */
    2696                 :             : 
    2697                 :             :         /* Flattened value will no longer represent array accurately */
    2698                 :         309 :         eah->fvalue = NULL;
    2699                 :             :         /* And we don't know the flattened size either */
    2700                 :         309 :         eah->flat_size = 0;
    2701                 :             : 
    2702                 :             :         /* Update dimensionality info if needed */
    2703         [ +  + ]:         309 :         if (dimschanged)
    2704                 :             :         {
    2705                 :         302 :                 eah->ndims = ndim;
    2706                 :         302 :                 memcpy(eah->dims, dim, ndim * sizeof(int));
    2707                 :         302 :                 memcpy(eah->lbound, lb, ndim * sizeof(int));
    2708                 :         302 :         }
    2709                 :             : 
    2710                 :             :         /* Reposition items if needed, and fill addedbefore items with nulls */
    2711         [ +  + ]:         309 :         if (addedbefore > 0)
    2712                 :             :         {
    2713                 :          13 :                 memmove(dvalues + addedbefore, dvalues, eah->nelems * sizeof(Datum));
    2714         [ +  + ]:          26 :                 for (i = 0; i < addedbefore; i++)
    2715                 :          13 :                         dvalues[i] = (Datum) 0;
    2716         [ +  - ]:          13 :                 if (dnulls)
    2717                 :             :                 {
    2718                 :           0 :                         memmove(dnulls + addedbefore, dnulls, eah->nelems * sizeof(bool));
    2719         [ #  # ]:           0 :                         for (i = 0; i < addedbefore; i++)
    2720                 :           0 :                                 dnulls[i] = true;
    2721                 :           0 :                 }
    2722                 :          13 :                 eah->nelems += addedbefore;
    2723                 :          13 :         }
    2724                 :             : 
    2725                 :             :         /* fill addedafter items with nulls */
    2726         [ +  + ]:         309 :         if (addedafter > 0)
    2727                 :             :         {
    2728         [ +  + ]:         578 :                 for (i = 0; i < addedafter; i++)
    2729                 :         289 :                         dvalues[eah->nelems + i] = (Datum) 0;
    2730         [ +  - ]:         289 :                 if (dnulls)
    2731                 :             :                 {
    2732         [ #  # ]:           0 :                         for (i = 0; i < addedafter; i++)
    2733                 :           0 :                                 dnulls[eah->nelems + i] = true;
    2734                 :           0 :                 }
    2735                 :         289 :                 eah->nelems += addedafter;
    2736                 :         289 :         }
    2737                 :             : 
    2738                 :             :         /* Grab old element value for pfree'ing, if needed. */
    2739   [ +  +  -  +  :         309 :         if (!eah->typbyval && (dnulls == NULL || !dnulls[offset]))
                   #  # ]
    2740                 :         126 :                 oldValue = (char *) DatumGetPointer(dvalues[offset]);
    2741                 :             :         else
    2742                 :         183 :                 oldValue = NULL;
    2743                 :             : 
    2744                 :             :         /* And finally we can insert the new element. */
    2745                 :         309 :         dvalues[offset] = dataValue;
    2746         [ -  + ]:         309 :         if (dnulls)
    2747                 :           0 :                 dnulls[offset] = isNull;
    2748                 :             : 
    2749                 :             :         /*
    2750                 :             :          * Free old element if needed; this keeps repeated element replacements
    2751                 :             :          * from bloating the array's storage.  If the pfree somehow fails, it
    2752                 :             :          * won't corrupt the array.
    2753                 :             :          */
    2754         [ -  + ]:         309 :         if (oldValue)
    2755                 :             :         {
    2756                 :             :                 /* Don't try to pfree a part of the original flat array */
    2757   [ #  #  #  # ]:           0 :                 if (oldValue < eah->fstartptr || oldValue >= eah->fendptr)
    2758                 :           0 :                         pfree(oldValue);
    2759                 :           0 :         }
    2760                 :             : 
    2761                 :             :         /* Done, return standard TOAST pointer for object */
    2762                 :         618 :         return EOHPGetRWDatum(&eah->hdr);
    2763                 :         309 : }
    2764                 :             : 
    2765                 :             : /*
    2766                 :             :  * array_set_slice :
    2767                 :             :  *                This routine sets the value of a range of array locations (specified
    2768                 :             :  *                by upper and lower subscript values) to new values passed as
    2769                 :             :  *                another array.
    2770                 :             :  *
    2771                 :             :  * This handles both ordinary varlena arrays and fixed-length arrays.
    2772                 :             :  *
    2773                 :             :  * Inputs:
    2774                 :             :  *      arraydatum: the initial array object (mustn't be NULL)
    2775                 :             :  *      nSubscripts: number of subscripts supplied (must be same for upper/lower)
    2776                 :             :  *      upperIndx[]: the upper subscript values
    2777                 :             :  *      lowerIndx[]: the lower subscript values
    2778                 :             :  *      upperProvided[]: true for provided upper subscript values
    2779                 :             :  *      lowerProvided[]: true for provided lower subscript values
    2780                 :             :  *      srcArrayDatum: the source for the inserted values
    2781                 :             :  *      isNull: indicates whether srcArrayDatum is NULL
    2782                 :             :  *      arraytyplen: pg_type.typlen for the array type
    2783                 :             :  *      elmlen: pg_type.typlen for the array's element type
    2784                 :             :  *      elmbyval: pg_type.typbyval for the array's element type
    2785                 :             :  *      elmalign: pg_type.typalign for the array's element type
    2786                 :             :  *
    2787                 :             :  * Result:
    2788                 :             :  *                A new array is returned, just like the old except for the
    2789                 :             :  *                modified range.  The original array object is not changed.
    2790                 :             :  *
    2791                 :             :  * Omitted upper and lower subscript values are replaced by the corresponding
    2792                 :             :  * array bound.
    2793                 :             :  *
    2794                 :             :  * For one-dimensional arrays only, we allow the array to be extended
    2795                 :             :  * by assigning to positions outside the existing subscript range; any
    2796                 :             :  * positions between the existing elements and the new ones are set to NULLs.
    2797                 :             :  * (XXX TODO: allow a corresponding behavior for multidimensional arrays)
    2798                 :             :  *
    2799                 :             :  * NOTE: we assume it is OK to scribble on the provided index arrays
    2800                 :             :  * lowerIndx[] and upperIndx[]; also, these arrays must be of size MAXDIM
    2801                 :             :  * even when nSubscripts is less.  These are generally just temporaries.
    2802                 :             :  *
    2803                 :             :  * NOTE: For assignments, we throw an error for silly subscripts etc,
    2804                 :             :  * rather than returning a NULL or empty array as the fetch operations do.
    2805                 :             :  */
    2806                 :             : Datum
    2807                 :          43 : array_set_slice(Datum arraydatum,
    2808                 :             :                                 int nSubscripts,
    2809                 :             :                                 int *upperIndx,
    2810                 :             :                                 int *lowerIndx,
    2811                 :             :                                 bool *upperProvided,
    2812                 :             :                                 bool *lowerProvided,
    2813                 :             :                                 Datum srcArrayDatum,
    2814                 :             :                                 bool isNull,
    2815                 :             :                                 int arraytyplen,
    2816                 :             :                                 int elmlen,
    2817                 :             :                                 bool elmbyval,
    2818                 :             :                                 char elmalign)
    2819                 :             : {
    2820                 :          43 :         ArrayType  *array;
    2821                 :          43 :         ArrayType  *srcArray;
    2822                 :          43 :         ArrayType  *newarray;
    2823                 :          43 :         int                     i,
    2824                 :             :                                 ndim,
    2825                 :             :                                 dim[MAXDIM],
    2826                 :             :                                 lb[MAXDIM],
    2827                 :             :                                 span[MAXDIM];
    2828                 :          43 :         bool            newhasnulls;
    2829                 :          43 :         int                     nitems,
    2830                 :             :                                 nsrcitems,
    2831                 :             :                                 olddatasize,
    2832                 :             :                                 newsize,
    2833                 :             :                                 olditemsize,
    2834                 :             :                                 newitemsize,
    2835                 :             :                                 overheadlen,
    2836                 :             :                                 oldoverheadlen,
    2837                 :             :                                 addedbefore,
    2838                 :             :                                 addedafter,
    2839                 :             :                                 lenbefore,
    2840                 :             :                                 lenafter,
    2841                 :             :                                 itemsbefore,
    2842                 :             :                                 itemsafter,
    2843                 :             :                                 nolditems;
    2844                 :             : 
    2845                 :             :         /* Currently, assignment from a NULL source array is a no-op */
    2846         [ -  + ]:          43 :         if (isNull)
    2847                 :           0 :                 return arraydatum;
    2848                 :             : 
    2849         [ +  - ]:          43 :         if (arraytyplen > 0)
    2850                 :             :         {
    2851                 :             :                 /*
    2852                 :             :                  * fixed-length arrays -- not got round to doing this...
    2853                 :             :                  */
    2854   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    2855                 :             :                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    2856                 :             :                                  errmsg("updates on slices of fixed-length arrays not implemented")));
    2857                 :           0 :         }
    2858                 :             : 
    2859                 :             :         /* detoast arrays if necessary */
    2860                 :          43 :         array = DatumGetArrayTypeP(arraydatum);
    2861                 :          43 :         srcArray = DatumGetArrayTypeP(srcArrayDatum);
    2862                 :             : 
    2863                 :             :         /* note: we assume srcArray contains no toasted elements */
    2864                 :             : 
    2865                 :          43 :         ndim = ARR_NDIM(array);
    2866                 :             : 
    2867                 :             :         /*
    2868                 :             :          * if number of dims is zero, i.e. an empty array, create an array with
    2869                 :             :          * nSubscripts dimensions, and set the upper and lower bounds to the
    2870                 :             :          * supplied subscripts
    2871                 :             :          */
    2872         [ +  + ]:          43 :         if (ndim == 0)
    2873                 :             :         {
    2874                 :           9 :                 Datum      *dvalues;
    2875                 :           9 :                 bool       *dnulls;
    2876                 :           9 :                 int                     nelems;
    2877                 :           9 :                 Oid                     elmtype = ARR_ELEMTYPE(array);
    2878                 :             : 
    2879                 :           9 :                 deconstruct_array(srcArray, elmtype, elmlen, elmbyval, elmalign,
    2880                 :             :                                                   &dvalues, &dnulls, &nelems);
    2881                 :             : 
    2882         [ +  + ]:          18 :                 for (i = 0; i < nSubscripts; i++)
    2883                 :             :                 {
    2884         [ +  + ]:          12 :                         if (!upperProvided[i] || !lowerProvided[i])
    2885   [ +  -  +  - ]:           1 :                                 ereport(ERROR,
    2886                 :             :                                                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    2887                 :             :                                                  errmsg("array slice subscript must provide both boundaries"),
    2888                 :             :                                                  errdetail("When assigning to a slice of an empty array value,"
    2889                 :             :                                                                    " slice boundaries must be fully specified.")));
    2890                 :             : 
    2891                 :             :                         /* compute "upperIndx[i] - lowerIndx[i] + 1", detecting overflow */
    2892         [ +  + ]:          11 :                         if (pg_sub_s32_overflow(upperIndx[i], lowerIndx[i], &dim[i]) ||
    2893                 :           9 :                                 pg_add_s32_overflow(dim[i], 1, &dim[i]))
    2894   [ +  -  +  - ]:           2 :                                 ereport(ERROR,
    2895                 :             :                                                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    2896                 :             :                                                  errmsg("array size exceeds the maximum allowed (%zu)",
    2897                 :             :                                                                 MaxArraySize)));
    2898                 :             : 
    2899                 :           9 :                         lb[i] = lowerIndx[i];
    2900                 :           9 :                 }
    2901                 :             : 
    2902                 :             :                 /* complain if too few source items; we ignore extras, however */
    2903         [ +  - ]:           6 :                 if (nelems < ArrayGetNItems(nSubscripts, dim))
    2904   [ #  #  #  # ]:           0 :                         ereport(ERROR,
    2905                 :             :                                         (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    2906                 :             :                                          errmsg("source array too small")));
    2907                 :             : 
    2908                 :          12 :                 return PointerGetDatum(construct_md_array(dvalues, dnulls, nSubscripts,
    2909                 :           6 :                                                                                                   dim, lb, elmtype,
    2910                 :           6 :                                                                                                   elmlen, elmbyval, elmalign));
    2911                 :           6 :         }
    2912                 :             : 
    2913         [ +  - ]:          34 :         if (ndim < nSubscripts || ndim <= 0 || ndim > MAXDIM)
    2914   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    2915                 :             :                                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    2916                 :             :                                  errmsg("wrong number of array subscripts")));
    2917                 :             : 
    2918                 :             :         /* copy dim/lb since we may modify them */
    2919                 :          34 :         memcpy(dim, ARR_DIMS(array), ndim * sizeof(int));
    2920                 :          34 :         memcpy(lb, ARR_LBOUND(array), ndim * sizeof(int));
    2921                 :             : 
    2922         [ +  + ]:          34 :         newhasnulls = (ARR_HASNULL(array) || ARR_HASNULL(srcArray));
    2923                 :          34 :         addedbefore = addedafter = 0;
    2924                 :             : 
    2925                 :             :         /*
    2926                 :             :          * Check subscripts.  We assume the existing subscripts passed
    2927                 :             :          * ArrayCheckBounds, so that dim[i] + lb[i] can be computed without
    2928                 :             :          * overflow.  But we must beware of other overflows in our calculations of
    2929                 :             :          * new dim[] values.
    2930                 :             :          */
    2931         [ +  + ]:          34 :         if (ndim == 1)
    2932                 :             :         {
    2933         [ +  - ]:          29 :                 Assert(nSubscripts == 1);
    2934         [ +  + ]:          29 :                 if (!lowerProvided[0])
    2935                 :           6 :                         lowerIndx[0] = lb[0];
    2936         [ +  + ]:          29 :                 if (!upperProvided[0])
    2937                 :           7 :                         upperIndx[0] = dim[0] + lb[0] - 1;
    2938         [ +  - ]:          29 :                 if (lowerIndx[0] > upperIndx[0])
    2939   [ #  #  #  # ]:           0 :                         ereport(ERROR,
    2940                 :             :                                         (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    2941                 :             :                                          errmsg("upper bound cannot be less than lower bound")));
    2942         [ +  + ]:          29 :                 if (lowerIndx[0] < lb[0])
    2943                 :             :                 {
    2944                 :             :                         /* addedbefore = lb[0] - lowerIndx[0]; */
    2945                 :             :                         /* dim[0] += addedbefore; */
    2946         [ +  - ]:           8 :                         if (pg_sub_s32_overflow(lb[0], lowerIndx[0], &addedbefore) ||
    2947                 :           8 :                                 pg_add_s32_overflow(dim[0], addedbefore, &dim[0]))
    2948   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
    2949                 :             :                                                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    2950                 :             :                                                  errmsg("array size exceeds the maximum allowed (%zu)",
    2951                 :             :                                                                 MaxArraySize)));
    2952                 :           8 :                         lb[0] = lowerIndx[0];
    2953         [ +  + ]:           8 :                         if (addedbefore > 1)
    2954                 :           6 :                                 newhasnulls = true; /* will insert nulls */
    2955                 :           8 :                 }
    2956         [ +  + ]:          29 :                 if (upperIndx[0] >= (dim[0] + lb[0]))
    2957                 :             :                 {
    2958                 :             :                         /* addedafter = upperIndx[0] - (dim[0] + lb[0]) + 1; */
    2959                 :             :                         /* dim[0] += addedafter; */
    2960         [ +  + ]:          10 :                         if (pg_sub_s32_overflow(upperIndx[0], dim[0] + lb[0], &addedafter) ||
    2961                 :           9 :                                 pg_add_s32_overflow(addedafter, 1, &addedafter) ||
    2962                 :           9 :                                 pg_add_s32_overflow(dim[0], addedafter, &dim[0]))
    2963   [ +  -  +  - ]:           1 :                                 ereport(ERROR,
    2964                 :             :                                                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    2965                 :             :                                                  errmsg("array size exceeds the maximum allowed (%zu)",
    2966                 :             :                                                                 MaxArraySize)));
    2967         [ +  + ]:           9 :                         if (addedafter > 1)
    2968                 :           6 :                                 newhasnulls = true; /* will insert nulls */
    2969                 :           9 :                 }
    2970                 :          28 :         }
    2971                 :             :         else
    2972                 :             :         {
    2973                 :             :                 /*
    2974                 :             :                  * XXX currently we do not support extending multi-dimensional arrays
    2975                 :             :                  * during assignment
    2976                 :             :                  */
    2977         [ +  + ]:          17 :                 for (i = 0; i < nSubscripts; i++)
    2978                 :             :                 {
    2979         [ +  + ]:          12 :                         if (!lowerProvided[i])
    2980                 :           2 :                                 lowerIndx[i] = lb[i];
    2981         [ +  + ]:          12 :                         if (!upperProvided[i])
    2982                 :           4 :                                 upperIndx[i] = dim[i] + lb[i] - 1;
    2983         [ +  - ]:          12 :                         if (lowerIndx[i] > upperIndx[i])
    2984   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
    2985                 :             :                                                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    2986                 :             :                                                  errmsg("upper bound cannot be less than lower bound")));
    2987         [ +  - ]:          12 :                         if (lowerIndx[i] < lb[i] ||
    2988                 :          12 :                                 upperIndx[i] >= (dim[i] + lb[i]))
    2989   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
    2990                 :             :                                                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    2991                 :             :                                                  errmsg("array subscript out of range")));
    2992                 :          12 :                 }
    2993                 :             :                 /* fill any missing subscript positions with full array range */
    2994         [ +  - ]:           5 :                 for (; i < ndim; i++)
    2995                 :             :                 {
    2996                 :           0 :                         lowerIndx[i] = lb[i];
    2997                 :           0 :                         upperIndx[i] = dim[i] + lb[i] - 1;
    2998         [ #  # ]:           0 :                         if (lowerIndx[i] > upperIndx[i])
    2999   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
    3000                 :             :                                                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    3001                 :             :                                                  errmsg("upper bound cannot be less than lower bound")));
    3002                 :           0 :                 }
    3003                 :             :         }
    3004                 :             : 
    3005                 :             :         /* Do this mainly to check for overflow */
    3006                 :          33 :         nitems = ArrayGetNItems(ndim, dim);
    3007                 :          33 :         ArrayCheckBounds(ndim, dim, lb);
    3008                 :             : 
    3009                 :             :         /*
    3010                 :             :          * Make sure source array has enough entries.  Note we ignore the shape of
    3011                 :             :          * the source array and just read entries serially.
    3012                 :             :          */
    3013                 :          33 :         mda_get_range(ndim, span, lowerIndx, upperIndx);
    3014                 :          33 :         nsrcitems = ArrayGetNItems(ndim, span);
    3015         [ +  + ]:          33 :         if (nsrcitems > ArrayGetNItems(ARR_NDIM(srcArray), ARR_DIMS(srcArray)))
    3016   [ +  -  +  - ]:           1 :                 ereport(ERROR,
    3017                 :             :                                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    3018                 :             :                                  errmsg("source array too small")));
    3019                 :             : 
    3020                 :             :         /*
    3021                 :             :          * Compute space occupied by new entries, space occupied by replaced
    3022                 :             :          * entries, and required space for new array.
    3023                 :             :          */
    3024         [ +  + ]:          32 :         if (newhasnulls)
    3025                 :          16 :                 overheadlen = ARR_OVERHEAD_WITHNULLS(ndim, nitems);
    3026                 :             :         else
    3027                 :          16 :                 overheadlen = ARR_OVERHEAD_NONULLS(ndim);
    3028         [ +  + ]:          64 :         newitemsize = array_nelems_size(ARR_DATA_PTR(srcArray), 0,
    3029         [ +  + ]:          32 :                                                                         ARR_NULLBITMAP(srcArray), nsrcitems,
    3030                 :          32 :                                                                         elmlen, elmbyval, elmalign);
    3031         [ +  + ]:          32 :         oldoverheadlen = ARR_DATA_OFFSET(array);
    3032                 :          32 :         olddatasize = ARR_SIZE(array) - oldoverheadlen;
    3033         [ +  + ]:          32 :         if (ndim > 1)
    3034                 :             :         {
    3035                 :             :                 /*
    3036                 :             :                  * here we do not need to cope with extension of the array; it would
    3037                 :             :                  * be a lot more complicated if we had to do so...
    3038                 :             :                  */
    3039         [ -  + ]:          10 :                 olditemsize = array_slice_size(ARR_DATA_PTR(array),
    3040         [ -  + ]:           5 :                                                                            ARR_NULLBITMAP(array),
    3041                 :           5 :                                                                            ndim, dim, lb,
    3042                 :           5 :                                                                            lowerIndx, upperIndx,
    3043                 :           5 :                                                                            elmlen, elmbyval, elmalign);
    3044                 :           5 :                 lenbefore = lenafter = 0;       /* keep compiler quiet */
    3045                 :           5 :                 itemsbefore = itemsafter = nolditems = 0;
    3046                 :           5 :         }
    3047                 :             :         else
    3048                 :             :         {
    3049                 :             :                 /*
    3050                 :             :                  * here we must allow for possibility of slice larger than orig array
    3051                 :             :                  * and/or not adjacent to orig array subscripts
    3052                 :             :                  */
    3053                 :          27 :                 int                     oldlb = ARR_LBOUND(array)[0];
    3054                 :          27 :                 int                     oldub = oldlb + ARR_DIMS(array)[0] - 1;
    3055         [ +  + ]:          27 :                 int                     slicelb = Max(oldlb, lowerIndx[0]);
    3056         [ +  + ]:          27 :                 int                     sliceub = Min(oldub, upperIndx[0]);
    3057         [ +  + ]:          27 :                 char       *oldarraydata = ARR_DATA_PTR(array);
    3058         [ +  + ]:          27 :                 bits8      *oldarraybitmap = ARR_NULLBITMAP(array);
    3059                 :             : 
    3060                 :             :                 /* count/size of old array entries that will go before the slice */
    3061         [ +  + ]:          27 :                 itemsbefore = Min(slicelb, oldub + 1) - oldlb;
    3062                 :          54 :                 lenbefore = array_nelems_size(oldarraydata, 0, oldarraybitmap,
    3063                 :          27 :                                                                           itemsbefore,
    3064                 :          27 :                                                                           elmlen, elmbyval, elmalign);
    3065                 :             :                 /* count/size of old array entries that will be replaced by slice */
    3066         [ +  + ]:          27 :                 if (slicelb > sliceub)
    3067                 :             :                 {
    3068                 :           9 :                         nolditems = 0;
    3069                 :           9 :                         olditemsize = 0;
    3070                 :           9 :                 }
    3071                 :             :                 else
    3072                 :             :                 {
    3073                 :          18 :                         nolditems = sliceub - slicelb + 1;
    3074                 :          36 :                         olditemsize = array_nelems_size(oldarraydata + lenbefore,
    3075                 :          18 :                                                                                         itemsbefore, oldarraybitmap,
    3076                 :          18 :                                                                                         nolditems,
    3077                 :          18 :                                                                                         elmlen, elmbyval, elmalign);
    3078                 :             :                 }
    3079                 :             :                 /* count/size of old array entries that will go after the slice */
    3080         [ +  + ]:          27 :                 itemsafter = oldub + 1 - Max(sliceub + 1, oldlb);
    3081                 :          27 :                 lenafter = olddatasize - lenbefore - olditemsize;
    3082                 :          27 :         }
    3083                 :             : 
    3084                 :          32 :         newsize = overheadlen + olddatasize - olditemsize + newitemsize;
    3085                 :             : 
    3086                 :          32 :         newarray = (ArrayType *) palloc0(newsize);
    3087                 :          32 :         SET_VARSIZE(newarray, newsize);
    3088                 :          32 :         newarray->ndim = ndim;
    3089         [ +  + ]:          32 :         newarray->dataoffset = newhasnulls ? overheadlen : 0;
    3090                 :          32 :         newarray->elemtype = ARR_ELEMTYPE(array);
    3091                 :          32 :         memcpy(ARR_DIMS(newarray), dim, ndim * sizeof(int));
    3092                 :          32 :         memcpy(ARR_LBOUND(newarray), lb, ndim * sizeof(int));
    3093                 :             : 
    3094         [ +  + ]:          32 :         if (ndim > 1)
    3095                 :             :         {
    3096                 :             :                 /*
    3097                 :             :                  * here we do not need to cope with extension of the array; it would
    3098                 :             :                  * be a lot more complicated if we had to do so...
    3099                 :             :                  */
    3100                 :          10 :                 array_insert_slice(newarray, array, srcArray,
    3101                 :           5 :                                                    ndim, dim, lb,
    3102                 :           5 :                                                    lowerIndx, upperIndx,
    3103                 :           5 :                                                    elmlen, elmbyval, elmalign);
    3104                 :           5 :         }
    3105                 :             :         else
    3106                 :             :         {
    3107                 :             :                 /* fill in data */
    3108                 :          27 :                 memcpy((char *) newarray + overheadlen,
    3109                 :             :                            (char *) array + oldoverheadlen,
    3110                 :             :                            lenbefore);
    3111         [ +  + ]:          27 :                 memcpy((char *) newarray + overheadlen + lenbefore,
    3112                 :             :                            ARR_DATA_PTR(srcArray),
    3113                 :             :                            newitemsize);
    3114                 :          27 :                 memcpy((char *) newarray + overheadlen + lenbefore + newitemsize,
    3115                 :             :                            (char *) array + oldoverheadlen + lenbefore + olditemsize,
    3116                 :             :                            lenafter);
    3117                 :             :                 /* fill in nulls bitmap if needed */
    3118         [ +  + ]:          27 :                 if (newhasnulls)
    3119                 :             :                 {
    3120         [ +  - ]:          16 :                         bits8      *newnullbitmap = ARR_NULLBITMAP(newarray);
    3121         [ +  - ]:          16 :                         bits8      *oldnullbitmap = ARR_NULLBITMAP(array);
    3122                 :             : 
    3123                 :             :                         /* palloc0 above already marked any inserted positions as nulls */
    3124                 :          32 :                         array_bitmap_copy(newnullbitmap, addedbefore,
    3125                 :          16 :                                                           oldnullbitmap, 0,
    3126                 :          16 :                                                           itemsbefore);
    3127                 :          32 :                         array_bitmap_copy(newnullbitmap, lowerIndx[0] - lb[0],
    3128         [ +  + ]:          16 :                                                           ARR_NULLBITMAP(srcArray), 0,
    3129                 :          16 :                                                           nsrcitems);
    3130                 :          32 :                         array_bitmap_copy(newnullbitmap, addedbefore + itemsbefore + nolditems,
    3131                 :          16 :                                                           oldnullbitmap, itemsbefore + nolditems,
    3132                 :          16 :                                                           itemsafter);
    3133                 :          16 :                 }
    3134                 :             :         }
    3135                 :             : 
    3136                 :          32 :         return PointerGetDatum(newarray);
    3137                 :          38 : }
    3138                 :             : 
    3139                 :             : /*
    3140                 :             :  * array_ref : backwards compatibility wrapper for array_get_element
    3141                 :             :  *
    3142                 :             :  * This only works for detoasted/flattened varlena arrays, since the array
    3143                 :             :  * argument is declared as "ArrayType *".  However there's enough code like
    3144                 :             :  * that to justify preserving this API.
    3145                 :             :  */
    3146                 :             : Datum
    3147                 :        4681 : array_ref(ArrayType *array, int nSubscripts, int *indx,
    3148                 :             :                   int arraytyplen, int elmlen, bool elmbyval, char elmalign,
    3149                 :             :                   bool *isNull)
    3150                 :             : {
    3151                 :        9362 :         return array_get_element(PointerGetDatum(array), nSubscripts, indx,
    3152                 :        4681 :                                                          arraytyplen, elmlen, elmbyval, elmalign,
    3153                 :        4681 :                                                          isNull);
    3154                 :             : }
    3155                 :             : 
    3156                 :             : /*
    3157                 :             :  * array_set : backwards compatibility wrapper for array_set_element
    3158                 :             :  *
    3159                 :             :  * This only works for detoasted/flattened varlena arrays, since the array
    3160                 :             :  * argument and result are declared as "ArrayType *".  However there's enough
    3161                 :             :  * code like that to justify preserving this API.
    3162                 :             :  */
    3163                 :             : ArrayType *
    3164                 :          16 : array_set(ArrayType *array, int nSubscripts, int *indx,
    3165                 :             :                   Datum dataValue, bool isNull,
    3166                 :             :                   int arraytyplen, int elmlen, bool elmbyval, char elmalign)
    3167                 :             : {
    3168                 :          16 :         return DatumGetArrayTypeP(array_set_element(PointerGetDatum(array),
    3169                 :             :                                                                                                 nSubscripts, indx,
    3170                 :             :                                                                                                 dataValue, isNull,
    3171                 :             :                                                                                                 arraytyplen,
    3172                 :             :                                                                                                 elmlen, elmbyval, elmalign));
    3173                 :             : }
    3174                 :             : 
    3175                 :             : /*
    3176                 :             :  * array_map()
    3177                 :             :  *
    3178                 :             :  * Map an array through an arbitrary expression.  Return a new array with
    3179                 :             :  * the same dimensions and each source element transformed by the given,
    3180                 :             :  * already-compiled expression.  Each source element is placed in the
    3181                 :             :  * innermost_caseval/innermost_casenull fields of the ExprState.
    3182                 :             :  *
    3183                 :             :  * Parameters are:
    3184                 :             :  * * arrayd: Datum representing array argument.
    3185                 :             :  * * exprstate: ExprState representing the per-element transformation.
    3186                 :             :  * * econtext: context for expression evaluation.
    3187                 :             :  * * retType: OID of element type of output array.  This must be the same as,
    3188                 :             :  *       or binary-compatible with, the result type of the expression.  It might
    3189                 :             :  *       be different from the input array's element type.
    3190                 :             :  * * amstate: workspace for array_map.  Must be zeroed by caller before
    3191                 :             :  *       first call, and not touched after that.
    3192                 :             :  *
    3193                 :             :  * It is legitimate to pass a freshly-zeroed ArrayMapState on each call,
    3194                 :             :  * but better performance can be had if the state can be preserved across
    3195                 :             :  * a series of calls.
    3196                 :             :  *
    3197                 :             :  * NB: caller must assure that input array is not NULL.  NULL elements in
    3198                 :             :  * the array are OK however.
    3199                 :             :  * NB: caller should be running in econtext's per-tuple memory context.
    3200                 :             :  */
    3201                 :             : Datum
    3202                 :          56 : array_map(Datum arrayd,
    3203                 :             :                   ExprState *exprstate, ExprContext *econtext,
    3204                 :             :                   Oid retType, ArrayMapState *amstate)
    3205                 :             : {
    3206                 :          56 :         AnyArrayType *v = DatumGetAnyArrayP(arrayd);
    3207                 :          56 :         ArrayType  *result;
    3208                 :          56 :         Datum      *values;
    3209                 :          56 :         bool       *nulls;
    3210                 :          56 :         int                *dim;
    3211                 :          56 :         int                     ndim;
    3212                 :          56 :         int                     nitems;
    3213                 :          56 :         int                     i;
    3214                 :          56 :         int32           nbytes = 0;
    3215                 :          56 :         int32           dataoffset;
    3216                 :          56 :         bool            hasnulls;
    3217                 :          56 :         Oid                     inpType;
    3218                 :          56 :         int                     inp_typlen;
    3219                 :          56 :         bool            inp_typbyval;
    3220                 :          56 :         char            inp_typalign;
    3221                 :          56 :         int                     typlen;
    3222                 :          56 :         bool            typbyval;
    3223                 :          56 :         char            typalign;
    3224                 :          56 :         array_iter      iter;
    3225                 :          56 :         ArrayMetaState *inp_extra;
    3226                 :          56 :         ArrayMetaState *ret_extra;
    3227                 :          56 :         Datum      *transform_source = exprstate->innermost_caseval;
    3228                 :          56 :         bool       *transform_source_isnull = exprstate->innermost_casenull;
    3229                 :             : 
    3230         [ +  - ]:          56 :         inpType = AARR_ELEMTYPE(v);
    3231         [ +  - ]:          56 :         ndim = AARR_NDIM(v);
    3232         [ +  - ]:          56 :         dim = AARR_DIMS(v);
    3233                 :          56 :         nitems = ArrayGetNItems(ndim, dim);
    3234                 :             : 
    3235                 :             :         /* Check for empty array */
    3236         [ +  + ]:          56 :         if (nitems <= 0)
    3237                 :             :         {
    3238                 :             :                 /* Return empty array */
    3239                 :           2 :                 return PointerGetDatum(construct_empty_array(retType));
    3240                 :             :         }
    3241                 :             : 
    3242                 :             :         /*
    3243                 :             :          * We arrange to look up info about input and return element types only
    3244                 :             :          * once per series of calls, assuming the element type doesn't change
    3245                 :             :          * underneath us.
    3246                 :             :          */
    3247                 :          54 :         inp_extra = &amstate->inp_extra;
    3248                 :          54 :         ret_extra = &amstate->ret_extra;
    3249                 :             : 
    3250         [ +  + ]:          54 :         if (inp_extra->element_type != inpType)
    3251                 :             :         {
    3252                 :         100 :                 get_typlenbyvalalign(inpType,
    3253                 :          50 :                                                          &inp_extra->typlen,
    3254                 :          50 :                                                          &inp_extra->typbyval,
    3255                 :          50 :                                                          &inp_extra->typalign);
    3256                 :          50 :                 inp_extra->element_type = inpType;
    3257                 :          50 :         }
    3258                 :          54 :         inp_typlen = inp_extra->typlen;
    3259                 :          54 :         inp_typbyval = inp_extra->typbyval;
    3260                 :          54 :         inp_typalign = inp_extra->typalign;
    3261                 :             : 
    3262         [ +  + ]:          54 :         if (ret_extra->element_type != retType)
    3263                 :             :         {
    3264                 :         100 :                 get_typlenbyvalalign(retType,
    3265                 :          50 :                                                          &ret_extra->typlen,
    3266                 :          50 :                                                          &ret_extra->typbyval,
    3267                 :          50 :                                                          &ret_extra->typalign);
    3268                 :          50 :                 ret_extra->element_type = retType;
    3269                 :          50 :         }
    3270                 :          54 :         typlen = ret_extra->typlen;
    3271                 :          54 :         typbyval = ret_extra->typbyval;
    3272                 :          54 :         typalign = ret_extra->typalign;
    3273                 :             : 
    3274                 :             :         /* Allocate temporary arrays for new values */
    3275                 :          54 :         values = (Datum *) palloc(nitems * sizeof(Datum));
    3276                 :          54 :         nulls = (bool *) palloc(nitems * sizeof(bool));
    3277                 :             : 
    3278                 :             :         /* Loop over source data */
    3279                 :          54 :         array_iter_setup(&iter, v);
    3280                 :          54 :         hasnulls = false;
    3281                 :             : 
    3282         [ +  + ]:         177 :         for (i = 0; i < nitems; i++)
    3283                 :             :         {
    3284                 :             :                 /* Get source element, checking for NULL */
    3285                 :         123 :                 *transform_source =
    3286                 :         246 :                         array_iter_next(&iter, transform_source_isnull, i,
    3287                 :         123 :                                                         inp_typlen, inp_typbyval, inp_typalign);
    3288                 :             : 
    3289                 :             :                 /* Apply the given expression to source element */
    3290                 :         123 :                 values[i] = ExecEvalExpr(exprstate, econtext, &nulls[i]);
    3291                 :             : 
    3292         [ +  + ]:         123 :                 if (nulls[i])
    3293                 :           2 :                         hasnulls = true;
    3294                 :             :                 else
    3295                 :             :                 {
    3296                 :             :                         /* Ensure data is not toasted */
    3297         [ +  + ]:         121 :                         if (typlen == -1)
    3298                 :          65 :                                 values[i] = PointerGetDatum(PG_DETOAST_DATUM(values[i]));
    3299                 :             :                         /* Update total result size */
    3300   [ +  +  -  +  :         121 :                         nbytes = att_addlength_datum(nbytes, typlen, values[i]);
                   #  # ]
    3301   [ +  +  +  +  :         121 :                         nbytes = att_align_nominal(nbytes, typalign);
             +  -  #  # ]
    3302                 :             :                         /* check for overflow of total request */
    3303         [ +  - ]:         121 :                         if (!AllocSizeIsValid(nbytes))
    3304   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
    3305                 :             :                                                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    3306                 :             :                                                  errmsg("array size exceeds the maximum allowed (%zu)",
    3307                 :             :                                                                 MaxAllocSize)));
    3308                 :             :                 }
    3309                 :         123 :         }
    3310                 :             : 
    3311                 :             :         /* Allocate and fill the result array */
    3312         [ +  + ]:          46 :         if (hasnulls)
    3313                 :             :         {
    3314                 :           1 :                 dataoffset = ARR_OVERHEAD_WITHNULLS(ndim, nitems);
    3315                 :           1 :                 nbytes += dataoffset;
    3316                 :           1 :         }
    3317                 :             :         else
    3318                 :             :         {
    3319                 :          45 :                 dataoffset = 0;                 /* marker for no null bitmap */
    3320                 :          45 :                 nbytes += ARR_OVERHEAD_NONULLS(ndim);
    3321                 :             :         }
    3322                 :          46 :         result = (ArrayType *) palloc0(nbytes);
    3323                 :          46 :         SET_VARSIZE(result, nbytes);
    3324                 :          46 :         result->ndim = ndim;
    3325                 :          46 :         result->dataoffset = dataoffset;
    3326                 :          46 :         result->elemtype = retType;
    3327         [ +  - ]:          46 :         memcpy(ARR_DIMS(result), AARR_DIMS(v), ndim * sizeof(int));
    3328         [ +  - ]:          46 :         memcpy(ARR_LBOUND(result), AARR_LBOUND(v), ndim * sizeof(int));
    3329                 :             : 
    3330                 :          92 :         CopyArrayEls(result,
    3331                 :          46 :                                  values, nulls, nitems,
    3332                 :          46 :                                  typlen, typbyval, typalign,
    3333                 :             :                                  false);
    3334                 :             : 
    3335                 :             :         /*
    3336                 :             :          * Note: do not risk trying to pfree the results of the called expression
    3337                 :             :          */
    3338                 :          46 :         pfree(values);
    3339                 :          46 :         pfree(nulls);
    3340                 :             : 
    3341                 :          46 :         return PointerGetDatum(result);
    3342                 :          48 : }
    3343                 :             : 
    3344                 :             : /*
    3345                 :             :  * construct_array      --- simple method for constructing an array object
    3346                 :             :  *
    3347                 :             :  * elems: array of Datum items to become the array contents
    3348                 :             :  *                (NULL element values are not supported).
    3349                 :             :  * nelems: number of items
    3350                 :             :  * elmtype, elmlen, elmbyval, elmalign: info for the datatype of the items
    3351                 :             :  *
    3352                 :             :  * A palloc'd 1-D array object is constructed and returned.  Note that
    3353                 :             :  * elem values will be copied into the object even if pass-by-ref type.
    3354                 :             :  * Also note the result will be 0-D not 1-D if nelems = 0.
    3355                 :             :  *
    3356                 :             :  * NOTE: it would be cleaner to look up the elmlen/elmbval/elmalign info
    3357                 :             :  * from the system catalogs, given the elmtype.  However, the caller is
    3358                 :             :  * in a better position to cache this info across multiple uses, or even
    3359                 :             :  * to hard-wire values if the element type is hard-wired.
    3360                 :             :  */
    3361                 :             : ArrayType *
    3362                 :       15212 : construct_array(Datum *elems, int nelems,
    3363                 :             :                                 Oid elmtype,
    3364                 :             :                                 int elmlen, bool elmbyval, char elmalign)
    3365                 :             : {
    3366                 :       15212 :         int                     dims[1];
    3367                 :       15212 :         int                     lbs[1];
    3368                 :             : 
    3369                 :       15212 :         dims[0] = nelems;
    3370                 :       15212 :         lbs[0] = 1;
    3371                 :             : 
    3372                 :       45636 :         return construct_md_array(elems, NULL, 1, dims, lbs,
    3373                 :       15212 :                                                           elmtype, elmlen, elmbyval, elmalign);
    3374                 :       15212 : }
    3375                 :             : 
    3376                 :             : /*
    3377                 :             :  * Like construct_array(), where elmtype must be a built-in type, and
    3378                 :             :  * elmlen/elmbyval/elmalign is looked up from hardcoded data.  This is often
    3379                 :             :  * useful when manipulating arrays from/for system catalogs.
    3380                 :             :  */
    3381                 :             : ArrayType *
    3382                 :       12715 : construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
    3383                 :             : {
    3384                 :       12715 :         int                     elmlen;
    3385                 :       12715 :         bool            elmbyval;
    3386                 :       12715 :         char            elmalign;
    3387                 :             : 
    3388   [ +  +  +  +  :       12715 :         switch (elmtype)
          +  +  +  -  +  
             +  -  -  - ]
    3389                 :             :         {
    3390                 :             :                 case CHAROID:
    3391                 :         267 :                         elmlen = 1;
    3392                 :         267 :                         elmbyval = true;
    3393                 :         267 :                         elmalign = TYPALIGN_CHAR;
    3394                 :         267 :                         break;
    3395                 :             : 
    3396                 :             :                 case CSTRINGOID:
    3397                 :         963 :                         elmlen = -2;
    3398                 :         963 :                         elmbyval = false;
    3399                 :         963 :                         elmalign = TYPALIGN_CHAR;
    3400                 :         963 :                         break;
    3401                 :             : 
    3402                 :             :                 case FLOAT4OID:
    3403                 :        3510 :                         elmlen = sizeof(float4);
    3404                 :        3510 :                         elmbyval = true;
    3405                 :        3510 :                         elmalign = TYPALIGN_INT;
    3406                 :        3510 :                         break;
    3407                 :             : 
    3408                 :             :                 case FLOAT8OID:
    3409                 :           8 :                         elmlen = sizeof(float8);
    3410                 :           8 :                         elmbyval = true;
    3411                 :           8 :                         elmalign = TYPALIGN_DOUBLE;
    3412                 :           8 :                         break;
    3413                 :             : 
    3414                 :             :                 case INT2OID:
    3415                 :        4457 :                         elmlen = sizeof(int16);
    3416                 :        4457 :                         elmbyval = true;
    3417                 :        4457 :                         elmalign = TYPALIGN_SHORT;
    3418                 :        4457 :                         break;
    3419                 :             : 
    3420                 :             :                 case INT4OID:
    3421                 :         526 :                         elmlen = sizeof(int32);
    3422                 :         526 :                         elmbyval = true;
    3423                 :         526 :                         elmalign = TYPALIGN_INT;
    3424                 :         526 :                         break;
    3425                 :             : 
    3426                 :             :                 case INT8OID:
    3427                 :           0 :                         elmlen = sizeof(int64);
    3428                 :           0 :                         elmbyval = true;
    3429                 :           0 :                         elmalign = TYPALIGN_DOUBLE;
    3430                 :           0 :                         break;
    3431                 :             : 
    3432                 :             :                 case NAMEOID:
    3433                 :          19 :                         elmlen = NAMEDATALEN;
    3434                 :          19 :                         elmbyval = false;
    3435                 :          19 :                         elmalign = TYPALIGN_CHAR;
    3436                 :          19 :                         break;
    3437                 :             : 
    3438                 :             :                 case OIDOID:
    3439                 :             :                 case REGTYPEOID:
    3440                 :        2063 :                         elmlen = sizeof(Oid);
    3441                 :        2063 :                         elmbyval = true;
    3442                 :        2063 :                         elmalign = TYPALIGN_INT;
    3443                 :        2063 :                         break;
    3444                 :             : 
    3445                 :             :                 case TEXTOID:
    3446                 :         902 :                         elmlen = -1;
    3447                 :         902 :                         elmbyval = false;
    3448                 :         902 :                         elmalign = TYPALIGN_INT;
    3449                 :         902 :                         break;
    3450                 :             : 
    3451                 :             :                 case TIDOID:
    3452                 :           0 :                         elmlen = sizeof(ItemPointerData);
    3453                 :           0 :                         elmbyval = false;
    3454                 :           0 :                         elmalign = TYPALIGN_SHORT;
    3455                 :           0 :                         break;
    3456                 :             : 
    3457                 :             :                 case XIDOID:
    3458                 :           0 :                         elmlen = sizeof(TransactionId);
    3459                 :           0 :                         elmbyval = true;
    3460                 :           0 :                         elmalign = TYPALIGN_INT;
    3461                 :           0 :                         break;
    3462                 :             : 
    3463                 :             :                 default:
    3464   [ #  #  #  # ]:           0 :                         elog(ERROR, "type %u not supported by construct_array_builtin()", elmtype);
    3465                 :             :                         /* keep compiler quiet */
    3466                 :           0 :                         elmlen = 0;
    3467                 :           0 :                         elmbyval = false;
    3468                 :           0 :                         elmalign = 0;
    3469                 :           0 :         }
    3470                 :             : 
    3471                 :       25430 :         return construct_array(elems, nelems, elmtype, elmlen, elmbyval, elmalign);
    3472                 :       12715 : }
    3473                 :             : 
    3474                 :             : /*
    3475                 :             :  * construct_md_array   --- simple method for constructing an array object
    3476                 :             :  *                                                      with arbitrary dimensions and possible NULLs
    3477                 :             :  *
    3478                 :             :  * elems: array of Datum items to become the array contents
    3479                 :             :  * nulls: array of is-null flags (can be NULL if no nulls)
    3480                 :             :  * ndims: number of dimensions
    3481                 :             :  * dims: integer array with size of each dimension
    3482                 :             :  * lbs: integer array with lower bound of each dimension
    3483                 :             :  * elmtype, elmlen, elmbyval, elmalign: info for the datatype of the items
    3484                 :             :  *
    3485                 :             :  * A palloc'd ndims-D array object is constructed and returned.  Note that
    3486                 :             :  * elem values will be copied into the object even if pass-by-ref type.
    3487                 :             :  * Also note the result will be 0-D not ndims-D if any dims[i] = 0.
    3488                 :             :  *
    3489                 :             :  * NOTE: it would be cleaner to look up the elmlen/elmbval/elmalign info
    3490                 :             :  * from the system catalogs, given the elmtype.  However, the caller is
    3491                 :             :  * in a better position to cache this info across multiple uses, or even
    3492                 :             :  * to hard-wire values if the element type is hard-wired.
    3493                 :             :  */
    3494                 :             : ArrayType *
    3495                 :      142978 : construct_md_array(Datum *elems,
    3496                 :             :                                    bool *nulls,
    3497                 :             :                                    int ndims,
    3498                 :             :                                    int *dims,
    3499                 :             :                                    int *lbs,
    3500                 :             :                                    Oid elmtype, int elmlen, bool elmbyval, char elmalign)
    3501                 :             : {
    3502                 :      142978 :         ArrayType  *result;
    3503                 :      142978 :         bool            hasnulls;
    3504                 :      142978 :         int32           nbytes;
    3505                 :      142978 :         int32           dataoffset;
    3506                 :      142978 :         int                     i;
    3507                 :      142978 :         int                     nelems;
    3508                 :             : 
    3509         [ +  - ]:      142978 :         if (ndims < 0)                               /* we do allow zero-dimension arrays */
    3510   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    3511                 :             :                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    3512                 :             :                                  errmsg("invalid number of dimensions: %d", ndims)));
    3513         [ +  - ]:      142978 :         if (ndims > MAXDIM)
    3514   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    3515                 :             :                                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    3516                 :             :                                  errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
    3517                 :             :                                                 ndims, MAXDIM)));
    3518                 :             : 
    3519                 :             :         /* This checks for overflow of the array dimensions */
    3520                 :      142978 :         nelems = ArrayGetNItems(ndims, dims);
    3521                 :      142978 :         ArrayCheckBounds(ndims, dims, lbs);
    3522                 :             : 
    3523                 :             :         /* if ndims <= 0 or any dims[i] == 0, return empty array */
    3524         [ +  + ]:      142978 :         if (nelems <= 0)
    3525                 :         794 :                 return construct_empty_array(elmtype);
    3526                 :             : 
    3527                 :             :         /* compute required space */
    3528                 :      142184 :         nbytes = 0;
    3529                 :      142184 :         hasnulls = false;
    3530         [ +  + ]:      887778 :         for (i = 0; i < nelems; i++)
    3531                 :             :         {
    3532   [ +  +  +  + ]:      745594 :                 if (nulls && nulls[i])
    3533                 :             :                 {
    3534                 :        5418 :                         hasnulls = true;
    3535                 :        5418 :                         continue;
    3536                 :             :                 }
    3537                 :             :                 /* make sure data is not toasted */
    3538         [ +  + ]:      740176 :                 if (elmlen == -1)
    3539                 :      134277 :                         elems[i] = PointerGetDatum(PG_DETOAST_DATUM(elems[i]));
    3540   [ +  +  +  +  :      740176 :                 nbytes = att_addlength_datum(nbytes, elmlen, elems[i]);
                   +  - ]
    3541   [ +  +  +  +  :      740176 :                 nbytes = att_align_nominal(nbytes, elmalign);
             +  +  +  - ]
    3542                 :             :                 /* check for overflow of total request */
    3543         [ +  - ]:      740176 :                 if (!AllocSizeIsValid(nbytes))
    3544   [ #  #  #  # ]:           0 :                         ereport(ERROR,
    3545                 :             :                                         (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    3546                 :             :                                          errmsg("array size exceeds the maximum allowed (%zu)",
    3547                 :             :                                                         MaxAllocSize)));
    3548                 :      740176 :         }
    3549                 :             : 
    3550                 :             :         /* Allocate and initialize result array */
    3551         [ +  + ]:      142184 :         if (hasnulls)
    3552                 :             :         {
    3553                 :        2889 :                 dataoffset = ARR_OVERHEAD_WITHNULLS(ndims, nelems);
    3554                 :        2889 :                 nbytes += dataoffset;
    3555                 :        2889 :         }
    3556                 :             :         else
    3557                 :             :         {
    3558                 :      139295 :                 dataoffset = 0;                 /* marker for no null bitmap */
    3559                 :      139295 :                 nbytes += ARR_OVERHEAD_NONULLS(ndims);
    3560                 :             :         }
    3561                 :      142184 :         result = (ArrayType *) palloc0(nbytes);
    3562                 :      142184 :         SET_VARSIZE(result, nbytes);
    3563                 :      142184 :         result->ndim = ndims;
    3564                 :      142184 :         result->dataoffset = dataoffset;
    3565                 :      142184 :         result->elemtype = elmtype;
    3566                 :      142184 :         memcpy(ARR_DIMS(result), dims, ndims * sizeof(int));
    3567                 :      142184 :         memcpy(ARR_LBOUND(result), lbs, ndims * sizeof(int));
    3568                 :             : 
    3569                 :      284368 :         CopyArrayEls(result,
    3570                 :      142184 :                                  elems, nulls, nelems,
    3571                 :      142184 :                                  elmlen, elmbyval, elmalign,
    3572                 :             :                                  false);
    3573                 :             : 
    3574                 :      142184 :         return result;
    3575                 :      142978 : }
    3576                 :             : 
    3577                 :             : /*
    3578                 :             :  * construct_empty_array        --- make a zero-dimensional array of given type
    3579                 :             :  */
    3580                 :             : ArrayType *
    3581                 :        1561 : construct_empty_array(Oid elmtype)
    3582                 :             : {
    3583                 :        1561 :         ArrayType  *result;
    3584                 :             : 
    3585                 :        1561 :         result = palloc0_object(ArrayType);
    3586                 :        1561 :         SET_VARSIZE(result, sizeof(ArrayType));
    3587                 :        1561 :         result->ndim = 0;
    3588                 :        1561 :         result->dataoffset = 0;
    3589                 :        1561 :         result->elemtype = elmtype;
    3590                 :        3122 :         return result;
    3591                 :        1561 : }
    3592                 :             : 
    3593                 :             : /*
    3594                 :             :  * construct_empty_expanded_array: make an empty expanded array
    3595                 :             :  * given only type information.  (metacache can be NULL if not needed.)
    3596                 :             :  */
    3597                 :             : ExpandedArrayHeader *
    3598                 :           4 : construct_empty_expanded_array(Oid element_type,
    3599                 :             :                                                            MemoryContext parentcontext,
    3600                 :             :                                                            ArrayMetaState *metacache)
    3601                 :             : {
    3602                 :           4 :         ArrayType  *array = construct_empty_array(element_type);
    3603                 :           4 :         Datum           d;
    3604                 :             : 
    3605                 :           4 :         d = expand_array(PointerGetDatum(array), parentcontext, metacache);
    3606                 :           4 :         pfree(array);
    3607                 :           8 :         return (ExpandedArrayHeader *) DatumGetEOHP(d);
    3608                 :           4 : }
    3609                 :             : 
    3610                 :             : /*
    3611                 :             :  * deconstruct_array  --- simple method for extracting data from an array
    3612                 :             :  *
    3613                 :             :  * array: array object to examine (must not be NULL)
    3614                 :             :  * elmtype, elmlen, elmbyval, elmalign: info for the datatype of the items
    3615                 :             :  * elemsp: return value, set to point to palloc'd array of Datum values
    3616                 :             :  * nullsp: return value, set to point to palloc'd array of isnull markers
    3617                 :             :  * nelemsp: return value, set to number of extracted values
    3618                 :             :  *
    3619                 :             :  * The caller may pass nullsp == NULL if it does not support NULLs in the
    3620                 :             :  * array.  Note that this produces a very uninformative error message,
    3621                 :             :  * so do it only in cases where a NULL is really not expected.
    3622                 :             :  *
    3623                 :             :  * If array elements are pass-by-ref data type, the returned Datums will
    3624                 :             :  * be pointers into the array object.
    3625                 :             :  *
    3626                 :             :  * NOTE: it would be cleaner to look up the elmlen/elmbval/elmalign info
    3627                 :             :  * from the system catalogs, given the elmtype.  However, the caller is
    3628                 :             :  * in a better position to cache this info across multiple uses, or even
    3629                 :             :  * to hard-wire values if the element type is hard-wired.
    3630                 :             :  */
    3631                 :             : void
    3632                 :      268607 : deconstruct_array(const ArrayType *array,
    3633                 :             :                                   Oid elmtype,
    3634                 :             :                                   int elmlen, bool elmbyval, char elmalign,
    3635                 :             :                                   Datum **elemsp, bool **nullsp, int *nelemsp)
    3636                 :             : {
    3637                 :      268607 :         Datum      *elems;
    3638                 :      268607 :         bool       *nulls;
    3639                 :      268607 :         int                     nelems;
    3640                 :      268607 :         char       *p;
    3641                 :      268607 :         bits8      *bitmap;
    3642                 :      268607 :         int                     bitmask;
    3643                 :      268607 :         int                     i;
    3644                 :             : 
    3645         [ +  - ]:      268607 :         Assert(ARR_ELEMTYPE(array) == elmtype);
    3646                 :             : 
    3647                 :      268607 :         nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
    3648                 :      268607 :         *elemsp = elems = palloc_array(Datum, nelems);
    3649         [ +  + ]:      268607 :         if (nullsp)
    3650                 :      171864 :                 *nullsp = nulls = palloc0_array(bool, nelems);
    3651                 :             :         else
    3652                 :       96743 :                 nulls = NULL;
    3653                 :      268607 :         *nelemsp = nelems;
    3654                 :             : 
    3655         [ +  + ]:      268607 :         p = ARR_DATA_PTR(array);
    3656         [ +  + ]:      268607 :         bitmap = ARR_NULLBITMAP(array);
    3657                 :      268607 :         bitmask = 1;
    3658                 :             : 
    3659         [ +  + ]:     4133908 :         for (i = 0; i < nelems; i++)
    3660                 :             :         {
    3661                 :             :                 /* Get source element, checking for NULL */
    3662   [ +  +  +  + ]:     3865301 :                 if (bitmap && (*bitmap & bitmask) == 0)
    3663                 :             :                 {
    3664                 :         529 :                         elems[i] = (Datum) 0;
    3665         [ +  - ]:         529 :                         if (nulls)
    3666                 :         529 :                                 nulls[i] = true;
    3667                 :             :                         else
    3668   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
    3669                 :             :                                                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    3670                 :             :                                                  errmsg("null array element not allowed in this context")));
    3671                 :         529 :                 }
    3672                 :             :                 else
    3673                 :             :                 {
    3674                 :     3864772 :                         elems[i] = fetch_att(p, elmbyval, elmlen);
    3675   [ +  +  +  +  :     3864772 :                         p = att_addlength_pointer(p, elmlen, p);
                   +  - ]
    3676   [ +  +  +  +  :     3864772 :                         p = (char *) att_align_nominal(p, elmalign);
             +  +  -  + ]
    3677                 :             :                 }
    3678                 :             : 
    3679                 :             :                 /* advance bitmap pointer if any */
    3680         [ +  + ]:     3865301 :                 if (bitmap)
    3681                 :             :                 {
    3682                 :         818 :                         bitmask <<= 1;
    3683         [ +  + ]:         818 :                         if (bitmask == 0x100)
    3684                 :             :                         {
    3685                 :          11 :                                 bitmap++;
    3686                 :          11 :                                 bitmask = 1;
    3687                 :          11 :                         }
    3688                 :         818 :                 }
    3689                 :     3865301 :         }
    3690                 :      268607 : }
    3691                 :             : 
    3692                 :             : /*
    3693                 :             :  * Like deconstruct_array(), where elmtype must be a built-in type, and
    3694                 :             :  * elmlen/elmbyval/elmalign is looked up from hardcoded data.  This is often
    3695                 :             :  * useful when manipulating arrays from/for system catalogs.
    3696                 :             :  */
    3697                 :             : void
    3698                 :       20372 : deconstruct_array_builtin(const ArrayType *array,
    3699                 :             :                                                   Oid elmtype,
    3700                 :             :                                                   Datum **elemsp, bool **nullsp, int *nelemsp)
    3701                 :             : {
    3702                 :       20372 :         int                     elmlen;
    3703                 :       20372 :         bool            elmbyval;
    3704                 :       20372 :         char            elmalign;
    3705                 :             : 
    3706   [ +  +  +  +  :       20372 :         switch (elmtype)
             +  +  +  - ]
    3707                 :             :         {
    3708                 :             :                 case CHAROID:
    3709                 :           3 :                         elmlen = 1;
    3710                 :           3 :                         elmbyval = true;
    3711                 :           3 :                         elmalign = TYPALIGN_CHAR;
    3712                 :           3 :                         break;
    3713                 :             : 
    3714                 :             :                 case CSTRINGOID:
    3715                 :         963 :                         elmlen = -2;
    3716                 :         963 :                         elmbyval = false;
    3717                 :         963 :                         elmalign = TYPALIGN_CHAR;
    3718                 :         963 :                         break;
    3719                 :             : 
    3720                 :             :                 case FLOAT8OID:
    3721                 :           5 :                         elmlen = sizeof(float8);
    3722                 :           5 :                         elmbyval = true;
    3723                 :           5 :                         elmalign = TYPALIGN_DOUBLE;
    3724                 :           5 :                         break;
    3725                 :             : 
    3726                 :             :                 case INT2OID:
    3727                 :         308 :                         elmlen = sizeof(int16);
    3728                 :         308 :                         elmbyval = true;
    3729                 :         308 :                         elmalign = TYPALIGN_SHORT;
    3730                 :         308 :                         break;
    3731                 :             : 
    3732                 :             :                 case OIDOID:
    3733                 :          27 :                         elmlen = sizeof(Oid);
    3734                 :          27 :                         elmbyval = true;
    3735                 :          27 :                         elmalign = TYPALIGN_INT;
    3736                 :          27 :                         break;
    3737                 :             : 
    3738                 :             :                 case TEXTOID:
    3739                 :       19059 :                         elmlen = -1;
    3740                 :       19059 :                         elmbyval = false;
    3741                 :       19059 :                         elmalign = TYPALIGN_INT;
    3742                 :       19059 :                         break;
    3743                 :             : 
    3744                 :             :                 case TIDOID:
    3745                 :           7 :                         elmlen = sizeof(ItemPointerData);
    3746                 :           7 :                         elmbyval = false;
    3747                 :           7 :                         elmalign = TYPALIGN_SHORT;
    3748                 :           7 :                         break;
    3749                 :             : 
    3750                 :             :                 default:
    3751   [ #  #  #  # ]:           0 :                         elog(ERROR, "type %u not supported by deconstruct_array_builtin()", elmtype);
    3752                 :             :                         /* keep compiler quiet */
    3753                 :           0 :                         elmlen = 0;
    3754                 :           0 :                         elmbyval = false;
    3755                 :           0 :                         elmalign = 0;
    3756                 :           0 :         }
    3757                 :             : 
    3758                 :       20372 :         deconstruct_array(array, elmtype, elmlen, elmbyval, elmalign, elemsp, nullsp, nelemsp);
    3759                 :       20372 : }
    3760                 :             : 
    3761                 :             : /*
    3762                 :             :  * array_contains_nulls --- detect whether an array has any null elements
    3763                 :             :  *
    3764                 :             :  * This gives an accurate answer, whereas testing ARR_HASNULL only tells
    3765                 :             :  * if the array *might* contain a null.
    3766                 :             :  */
    3767                 :             : bool
    3768                 :        1315 : array_contains_nulls(const ArrayType *array)
    3769                 :             : {
    3770                 :        1315 :         int                     nelems;
    3771                 :        1315 :         bits8      *bitmap;
    3772                 :        1315 :         int                     bitmask;
    3773                 :             : 
    3774                 :             :         /* Easy answer if there's no null bitmap */
    3775         [ +  + ]:        1315 :         if (!ARR_HASNULL(array))
    3776                 :        1305 :                 return false;
    3777                 :             : 
    3778                 :          10 :         nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
    3779                 :             : 
    3780         [ +  - ]:          10 :         bitmap = ARR_NULLBITMAP(array);
    3781                 :             : 
    3782                 :             :         /* check whole bytes of the bitmap byte-at-a-time */
    3783         [ +  + ]:          10 :         while (nelems >= 8)
    3784                 :             :         {
    3785         [ +  - ]:           3 :                 if (*bitmap != 0xFF)
    3786                 :           3 :                         return true;
    3787                 :           0 :                 bitmap++;
    3788                 :           0 :                 nelems -= 8;
    3789                 :             :         }
    3790                 :             : 
    3791                 :             :         /* check last partial byte */
    3792                 :           7 :         bitmask = 1;
    3793         [ +  - ]:          16 :         while (nelems > 0)
    3794                 :             :         {
    3795         [ +  + ]:          16 :                 if ((*bitmap & bitmask) == 0)
    3796                 :           7 :                         return true;
    3797                 :           9 :                 bitmask <<= 1;
    3798                 :           9 :                 nelems--;
    3799                 :             :         }
    3800                 :             : 
    3801                 :           0 :         return false;
    3802                 :        1315 : }
    3803                 :             : 
    3804                 :             : 
    3805                 :             : /*
    3806                 :             :  * array_eq :
    3807                 :             :  *                compares two arrays for equality
    3808                 :             :  * result :
    3809                 :             :  *                returns true if the arrays are equal, false otherwise.
    3810                 :             :  *
    3811                 :             :  * Note: we do not use array_cmp here, since equality may be meaningful in
    3812                 :             :  * datatypes that don't have a total ordering (and hence no btree support).
    3813                 :             :  */
    3814                 :             : Datum
    3815                 :        4353 : array_eq(PG_FUNCTION_ARGS)
    3816                 :             : {
    3817                 :        4353 :         LOCAL_FCINFO(locfcinfo, 2);
    3818                 :        4353 :         AnyArrayType *array1 = PG_GETARG_ANY_ARRAY_P(0);
    3819                 :        4353 :         AnyArrayType *array2 = PG_GETARG_ANY_ARRAY_P(1);
    3820                 :        4353 :         Oid                     collation = PG_GET_COLLATION();
    3821         [ +  + ]:        4353 :         int                     ndims1 = AARR_NDIM(array1);
    3822         [ +  + ]:        4353 :         int                     ndims2 = AARR_NDIM(array2);
    3823         [ +  + ]:        4353 :         int                *dims1 = AARR_DIMS(array1);
    3824         [ +  + ]:        4353 :         int                *dims2 = AARR_DIMS(array2);
    3825         [ +  + ]:        4353 :         int                *lbs1 = AARR_LBOUND(array1);
    3826         [ +  + ]:        4353 :         int                *lbs2 = AARR_LBOUND(array2);
    3827         [ +  + ]:        4353 :         Oid                     element_type = AARR_ELEMTYPE(array1);
    3828                 :        4353 :         bool            result = true;
    3829                 :        4353 :         int                     nitems;
    3830                 :        4353 :         TypeCacheEntry *typentry;
    3831                 :        4353 :         int                     typlen;
    3832                 :        4353 :         bool            typbyval;
    3833                 :        4353 :         char            typalign;
    3834                 :        4353 :         array_iter      it1;
    3835                 :        4353 :         array_iter      it2;
    3836                 :        4353 :         int                     i;
    3837                 :             : 
    3838   [ +  +  +  - ]:        4353 :         if (element_type != AARR_ELEMTYPE(array2))
    3839   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    3840                 :             :                                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    3841                 :             :                                  errmsg("cannot compare arrays of different element types")));
    3842                 :             : 
    3843                 :             :         /* fast path if the arrays do not have the same dimensionality */
    3844         [ +  + ]:        4353 :         if (ndims1 != ndims2 ||
    3845   [ +  +  -  + ]:        4144 :                 memcmp(dims1, dims2, ndims1 * sizeof(int)) != 0 ||
    3846                 :        3767 :                 memcmp(lbs1, lbs2, ndims1 * sizeof(int)) != 0)
    3847                 :         586 :                 result = false;
    3848                 :             :         else
    3849                 :             :         {
    3850                 :             :                 /*
    3851                 :             :                  * We arrange to look up the equality function only once per series of
    3852                 :             :                  * calls, assuming the element type doesn't change underneath us.  The
    3853                 :             :                  * typcache is used so that we have no memory leakage when being used
    3854                 :             :                  * as an index support function.
    3855                 :             :                  */
    3856                 :        3767 :                 typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
    3857   [ +  +  -  + ]:        3767 :                 if (typentry == NULL ||
    3858                 :        3725 :                         typentry->type_id != element_type)
    3859                 :             :                 {
    3860                 :          42 :                         typentry = lookup_type_cache(element_type,
    3861                 :             :                                                                                  TYPECACHE_EQ_OPR_FINFO);
    3862         [ +  - ]:          42 :                         if (!OidIsValid(typentry->eq_opr_finfo.fn_oid))
    3863   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
    3864                 :             :                                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
    3865                 :             :                                                  errmsg("could not identify an equality operator for type %s",
    3866                 :             :                                                                 format_type_be(element_type))));
    3867                 :          42 :                         fcinfo->flinfo->fn_extra = typentry;
    3868                 :          42 :                 }
    3869                 :        3767 :                 typlen = typentry->typlen;
    3870                 :        3767 :                 typbyval = typentry->typbyval;
    3871                 :        3767 :                 typalign = typentry->typalign;
    3872                 :             : 
    3873                 :             :                 /*
    3874                 :             :                  * apply the operator to each pair of array elements.
    3875                 :             :                  */
    3876                 :        3767 :                 InitFunctionCallInfoData(*locfcinfo, &typentry->eq_opr_finfo, 2,
    3877                 :             :                                                                  collation, NULL, NULL);
    3878                 :             : 
    3879                 :             :                 /* Loop over source data */
    3880                 :        3767 :                 nitems = ArrayGetNItems(ndims1, dims1);
    3881                 :        3767 :                 array_iter_setup(&it1, array1);
    3882                 :        3767 :                 array_iter_setup(&it2, array2);
    3883                 :             : 
    3884         [ +  + ]:       10669 :                 for (i = 0; i < nitems; i++)
    3885                 :             :                 {
    3886                 :        7061 :                         Datum           elt1;
    3887                 :        7061 :                         Datum           elt2;
    3888                 :        7061 :                         bool            isnull1;
    3889                 :        7061 :                         bool            isnull2;
    3890                 :        7061 :                         bool            oprresult;
    3891                 :             : 
    3892                 :             :                         /* Get elements, checking for NULL */
    3893                 :       14122 :                         elt1 = array_iter_next(&it1, &isnull1, i,
    3894                 :        7061 :                                                                    typlen, typbyval, typalign);
    3895                 :       14122 :                         elt2 = array_iter_next(&it2, &isnull2, i,
    3896                 :        7061 :                                                                    typlen, typbyval, typalign);
    3897                 :             : 
    3898                 :             :                         /*
    3899                 :             :                          * We consider two NULLs equal; NULL and not-NULL are unequal.
    3900                 :             :                          */
    3901   [ +  +  -  + ]:        7061 :                         if (isnull1 && isnull2)
    3902                 :           2 :                                 continue;
    3903   [ +  -  +  + ]:        7059 :                         if (isnull1 || isnull2)
    3904                 :             :                         {
    3905                 :          18 :                                 result = false;
    3906                 :          18 :                                 break;
    3907                 :             :                         }
    3908                 :             : 
    3909                 :             :                         /*
    3910                 :             :                          * Apply the operator to the element pair; treat NULL as false
    3911                 :             :                          */
    3912                 :        7041 :                         locfcinfo->args[0].value = elt1;
    3913                 :        7041 :                         locfcinfo->args[0].isnull = false;
    3914                 :        7041 :                         locfcinfo->args[1].value = elt2;
    3915                 :        7041 :                         locfcinfo->args[1].isnull = false;
    3916                 :        7041 :                         locfcinfo->isnull = false;
    3917                 :        7041 :                         oprresult = DatumGetBool(FunctionCallInvoke(locfcinfo));
    3918   [ +  -  +  + ]:        7041 :                         if (locfcinfo->isnull || !oprresult)
    3919                 :             :                         {
    3920                 :         141 :                                 result = false;
    3921                 :         141 :                                 break;
    3922                 :             :                         }
    3923   [ -  +  +  + ]:        7061 :                 }
    3924                 :             :         }
    3925                 :             : 
    3926                 :             :         /* Avoid leaking memory when handed toasted input. */
    3927   [ +  +  +  + ]:        4353 :         AARR_FREE_IF_COPY(array1, 0);
    3928   [ +  +  +  + ]:        4353 :         AARR_FREE_IF_COPY(array2, 1);
    3929                 :             : 
    3930                 :        8706 :         PG_RETURN_BOOL(result);
    3931                 :        4353 : }
    3932                 :             : 
    3933                 :             : 
    3934                 :             : /*-----------------------------------------------------------------------------
    3935                 :             :  * array-array bool operators:
    3936                 :             :  *              Given two arrays, iterate comparison operators
    3937                 :             :  *              over the array. Uses logic similar to text comparison
    3938                 :             :  *              functions, except element-by-element instead of
    3939                 :             :  *              character-by-character.
    3940                 :             :  *----------------------------------------------------------------------------
    3941                 :             :  */
    3942                 :             : 
    3943                 :             : Datum
    3944                 :         165 : array_ne(PG_FUNCTION_ARGS)
    3945                 :             : {
    3946                 :         165 :         PG_RETURN_BOOL(!DatumGetBool(array_eq(fcinfo)));
    3947                 :             : }
    3948                 :             : 
    3949                 :             : Datum
    3950                 :           3 : array_lt(PG_FUNCTION_ARGS)
    3951                 :             : {
    3952                 :           3 :         PG_RETURN_BOOL(array_cmp(fcinfo) < 0);
    3953                 :             : }
    3954                 :             : 
    3955                 :             : Datum
    3956                 :           3 : array_gt(PG_FUNCTION_ARGS)
    3957                 :             : {
    3958                 :           3 :         PG_RETURN_BOOL(array_cmp(fcinfo) > 0);
    3959                 :             : }
    3960                 :             : 
    3961                 :             : Datum
    3962                 :           3 : array_le(PG_FUNCTION_ARGS)
    3963                 :             : {
    3964                 :           3 :         PG_RETURN_BOOL(array_cmp(fcinfo) <= 0);
    3965                 :             : }
    3966                 :             : 
    3967                 :             : Datum
    3968                 :           3 : array_ge(PG_FUNCTION_ARGS)
    3969                 :             : {
    3970                 :           3 :         PG_RETURN_BOOL(array_cmp(fcinfo) >= 0);
    3971                 :             : }
    3972                 :             : 
    3973                 :             : Datum
    3974                 :     1159255 : btarraycmp(PG_FUNCTION_ARGS)
    3975                 :             : {
    3976                 :     1159255 :         PG_RETURN_INT32(array_cmp(fcinfo));
    3977                 :             : }
    3978                 :             : 
    3979                 :             : /*
    3980                 :             :  * array_cmp()
    3981                 :             :  * Internal comparison function for arrays.
    3982                 :             :  *
    3983                 :             :  * Returns -1, 0 or 1
    3984                 :             :  */
    3985                 :             : static int
    3986                 :     1159358 : array_cmp(FunctionCallInfo fcinfo)
    3987                 :             : {
    3988                 :     1159358 :         LOCAL_FCINFO(locfcinfo, 2);
    3989                 :     1159358 :         AnyArrayType *array1 = PG_GETARG_ANY_ARRAY_P(0);
    3990                 :     1159358 :         AnyArrayType *array2 = PG_GETARG_ANY_ARRAY_P(1);
    3991                 :     1159358 :         Oid                     collation = PG_GET_COLLATION();
    3992         [ -  + ]:     1159358 :         int                     ndims1 = AARR_NDIM(array1);
    3993         [ -  + ]:     1159358 :         int                     ndims2 = AARR_NDIM(array2);
    3994         [ -  + ]:     1159358 :         int                *dims1 = AARR_DIMS(array1);
    3995         [ -  + ]:     1159358 :         int                *dims2 = AARR_DIMS(array2);
    3996                 :     1159358 :         int                     nitems1 = ArrayGetNItems(ndims1, dims1);
    3997                 :     1159358 :         int                     nitems2 = ArrayGetNItems(ndims2, dims2);
    3998         [ -  + ]:     1159358 :         Oid                     element_type = AARR_ELEMTYPE(array1);
    3999                 :     1159358 :         int                     result = 0;
    4000                 :     1159358 :         TypeCacheEntry *typentry;
    4001                 :     1159358 :         int                     typlen;
    4002                 :     1159358 :         bool            typbyval;
    4003                 :     1159358 :         char            typalign;
    4004                 :     1159358 :         int                     min_nitems;
    4005                 :     1159358 :         array_iter      it1;
    4006                 :     1159358 :         array_iter      it2;
    4007                 :     1159358 :         int                     i;
    4008                 :             : 
    4009   [ -  +  +  + ]:     1159358 :         if (element_type != AARR_ELEMTYPE(array2))
    4010   [ +  -  +  - ]:           1 :                 ereport(ERROR,
    4011                 :             :                                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    4012                 :             :                                  errmsg("cannot compare arrays of different element types")));
    4013                 :             : 
    4014                 :             :         /*
    4015                 :             :          * We arrange to look up the comparison function only once per series of
    4016                 :             :          * calls, assuming the element type doesn't change underneath us. The
    4017                 :             :          * typcache is used so that we have no memory leakage when being used as
    4018                 :             :          * an index support function.
    4019                 :             :          */
    4020                 :     1159357 :         typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
    4021   [ +  +  -  + ]:     1159357 :         if (typentry == NULL ||
    4022                 :     1159218 :                 typentry->type_id != element_type)
    4023                 :             :         {
    4024                 :         139 :                 typentry = lookup_type_cache(element_type,
    4025                 :             :                                                                          TYPECACHE_CMP_PROC_FINFO);
    4026         [ +  + ]:         139 :                 if (!OidIsValid(typentry->cmp_proc_finfo.fn_oid))
    4027   [ +  -  +  - ]:           1 :                         ereport(ERROR,
    4028                 :             :                                         (errcode(ERRCODE_UNDEFINED_FUNCTION),
    4029                 :             :                                          errmsg("could not identify a comparison function for type %s",
    4030                 :             :                                                         format_type_be(element_type))));
    4031                 :         138 :                 fcinfo->flinfo->fn_extra = typentry;
    4032                 :         138 :         }
    4033                 :     1159356 :         typlen = typentry->typlen;
    4034                 :     1159356 :         typbyval = typentry->typbyval;
    4035                 :     1159356 :         typalign = typentry->typalign;
    4036                 :             : 
    4037                 :             :         /*
    4038                 :             :          * apply the operator to each pair of array elements.
    4039                 :             :          */
    4040                 :     1159356 :         InitFunctionCallInfoData(*locfcinfo, &typentry->cmp_proc_finfo, 2,
    4041                 :             :                                                          collation, NULL, NULL);
    4042                 :             : 
    4043                 :             :         /* Loop over source data */
    4044         [ +  + ]:     1159356 :         min_nitems = Min(nitems1, nitems2);
    4045                 :     1159356 :         array_iter_setup(&it1, array1);
    4046                 :     1159356 :         array_iter_setup(&it2, array2);
    4047                 :             : 
    4048         [ +  + ]:     2450829 :         for (i = 0; i < min_nitems; i++)
    4049                 :             :         {
    4050                 :     2139338 :                 Datum           elt1;
    4051                 :     2139338 :                 Datum           elt2;
    4052                 :     2139338 :                 bool            isnull1;
    4053                 :     2139338 :                 bool            isnull2;
    4054                 :     2139338 :                 int32           cmpresult;
    4055                 :             : 
    4056                 :             :                 /* Get elements, checking for NULL */
    4057                 :     2139338 :                 elt1 = array_iter_next(&it1, &isnull1, i, typlen, typbyval, typalign);
    4058                 :     2139338 :                 elt2 = array_iter_next(&it2, &isnull2, i, typlen, typbyval, typalign);
    4059                 :             : 
    4060                 :             :                 /*
    4061                 :             :                  * We consider two NULLs equal; NULL > not-NULL.
    4062                 :             :                  */
    4063   [ +  +  +  - ]:     2139338 :                 if (isnull1 && isnull2)
    4064                 :           0 :                         continue;
    4065         [ +  + ]:     2139338 :                 if (isnull1)
    4066                 :             :                 {
    4067                 :             :                         /* arg1 is greater than arg2 */
    4068                 :          16 :                         result = 1;
    4069                 :          16 :                         break;
    4070                 :             :                 }
    4071         [ +  + ]:     2139322 :                 if (isnull2)
    4072                 :             :                 {
    4073                 :             :                         /* arg1 is less than arg2 */
    4074                 :          30 :                         result = -1;
    4075                 :          30 :                         break;
    4076                 :             :                 }
    4077                 :             : 
    4078                 :             :                 /* Compare the pair of elements */
    4079                 :     2139292 :                 locfcinfo->args[0].value = elt1;
    4080                 :     2139292 :                 locfcinfo->args[0].isnull = false;
    4081                 :     2139292 :                 locfcinfo->args[1].value = elt2;
    4082                 :     2139292 :                 locfcinfo->args[1].isnull = false;
    4083                 :     2139292 :                 cmpresult = DatumGetInt32(FunctionCallInvoke(locfcinfo));
    4084                 :             : 
    4085                 :             :                 /* We don't expect comparison support functions to return null */
    4086         [ +  - ]:     2139292 :                 Assert(!locfcinfo->isnull);
    4087                 :             : 
    4088         [ +  + ]:     2139292 :                 if (cmpresult == 0)
    4089                 :     1291473 :                         continue;                       /* equal */
    4090                 :             : 
    4091         [ +  + ]:      847819 :                 if (cmpresult < 0)
    4092                 :             :                 {
    4093                 :             :                         /* arg1 is less than arg2 */
    4094                 :      498097 :                         result = -1;
    4095                 :      498097 :                         break;
    4096                 :             :                 }
    4097                 :             :                 else
    4098                 :             :                 {
    4099                 :             :                         /* arg1 is greater than arg2 */
    4100                 :      349722 :                         result = 1;
    4101                 :      349722 :                         break;
    4102                 :             :                 }
    4103      [ -  +  + ]:     2139338 :         }
    4104                 :             : 
    4105                 :             :         /*
    4106                 :             :          * If arrays contain same data (up to end of shorter one), apply
    4107                 :             :          * additional rules to sort by dimensionality.  The relative significance
    4108                 :             :          * of the different bits of information is historical; mainly we just care
    4109                 :             :          * that we don't say "equal" for arrays of different dimensionality.
    4110                 :             :          */
    4111         [ +  + ]:     1159356 :         if (result == 0)
    4112                 :             :         {
    4113         [ +  + ]:      311491 :                 if (nitems1 != nitems2)
    4114                 :        1383 :                         result = (nitems1 < nitems2) ? -1 : 1;
    4115         [ -  + ]:      310108 :                 else if (ndims1 != ndims2)
    4116                 :           0 :                         result = (ndims1 < ndims2) ? -1 : 1;
    4117                 :             :                 else
    4118                 :             :                 {
    4119         [ +  + ]:      620215 :                         for (i = 0; i < ndims1; i++)
    4120                 :             :                         {
    4121         [ -  + ]:      310107 :                                 if (dims1[i] != dims2[i])
    4122                 :             :                                 {
    4123                 :           0 :                                         result = (dims1[i] < dims2[i]) ? -1 : 1;
    4124                 :           0 :                                         break;
    4125                 :             :                                 }
    4126                 :      310107 :                         }
    4127         [ -  + ]:      310108 :                         if (result == 0)
    4128                 :             :                         {
    4129         [ +  - ]:      310108 :                                 int                *lbound1 = AARR_LBOUND(array1);
    4130         [ +  - ]:      310108 :                                 int                *lbound2 = AARR_LBOUND(array2);
    4131                 :             : 
    4132         [ +  + ]:      620215 :                                 for (i = 0; i < ndims1; i++)
    4133                 :             :                                 {
    4134         [ -  + ]:      310107 :                                         if (lbound1[i] != lbound2[i])
    4135                 :             :                                         {
    4136                 :           0 :                                                 result = (lbound1[i] < lbound2[i]) ? -1 : 1;
    4137                 :           0 :                                                 break;
    4138                 :             :                                         }
    4139                 :      310107 :                                 }
    4140                 :      310108 :                         }
    4141                 :             :                 }
    4142                 :      311491 :         }
    4143                 :             : 
    4144                 :             :         /* Avoid leaking memory when handed toasted input. */
    4145   [ -  +  +  + ]:     1159356 :         AARR_FREE_IF_COPY(array1, 0);
    4146   [ -  +  +  + ]:     1159356 :         AARR_FREE_IF_COPY(array2, 1);
    4147                 :             : 
    4148                 :     2318712 :         return result;
    4149                 :     1159356 : }
    4150                 :             : 
    4151                 :             : 
    4152                 :             : /*-----------------------------------------------------------------------------
    4153                 :             :  * array hashing
    4154                 :             :  *              Hash the elements and combine the results.
    4155                 :             :  *----------------------------------------------------------------------------
    4156                 :             :  */
    4157                 :             : 
    4158                 :             : Datum
    4159                 :        5882 : hash_array(PG_FUNCTION_ARGS)
    4160                 :             : {
    4161                 :        5882 :         LOCAL_FCINFO(locfcinfo, 1);
    4162                 :        5882 :         AnyArrayType *array = PG_GETARG_ANY_ARRAY_P(0);
    4163         [ +  + ]:        5882 :         int                     ndims = AARR_NDIM(array);
    4164         [ +  + ]:        5882 :         int                *dims = AARR_DIMS(array);
    4165         [ +  + ]:        5882 :         Oid                     element_type = AARR_ELEMTYPE(array);
    4166                 :        5882 :         uint32          result = 1;
    4167                 :        5882 :         int                     nitems;
    4168                 :        5882 :         TypeCacheEntry *typentry;
    4169                 :        5882 :         int                     typlen;
    4170                 :        5882 :         bool            typbyval;
    4171                 :        5882 :         char            typalign;
    4172                 :        5882 :         int                     i;
    4173                 :        5882 :         array_iter      iter;
    4174                 :             : 
    4175                 :             :         /*
    4176                 :             :          * We arrange to look up the hash function only once per series of calls,
    4177                 :             :          * assuming the element type doesn't change underneath us.  The typcache
    4178                 :             :          * is used so that we have no memory leakage when being used as an index
    4179                 :             :          * support function.
    4180                 :             :          */
    4181                 :        5882 :         typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
    4182   [ +  +  -  + ]:        5882 :         if (typentry == NULL ||
    4183                 :        5869 :                 typentry->type_id != element_type)
    4184                 :             :         {
    4185                 :          13 :                 typentry = lookup_type_cache(element_type,
    4186                 :             :                                                                          TYPECACHE_HASH_PROC_FINFO);
    4187   [ +  +  +  + ]:          13 :                 if (!OidIsValid(typentry->hash_proc_finfo.fn_oid) && element_type != RECORDOID)
    4188   [ +  -  +  - ]:           1 :                         ereport(ERROR,
    4189                 :             :                                         (errcode(ERRCODE_UNDEFINED_FUNCTION),
    4190                 :             :                                          errmsg("could not identify a hash function for type %s",
    4191                 :             :                                                         format_type_be(element_type))));
    4192                 :             : 
    4193                 :             :                 /*
    4194                 :             :                  * The type cache doesn't believe that record is hashable (see
    4195                 :             :                  * cache_record_field_properties()), but since we're here, we're
    4196                 :             :                  * committed to hashing, so we can assume it does.  Worst case, if any
    4197                 :             :                  * components of the record don't support hashing, we will fail at
    4198                 :             :                  * execution.
    4199                 :             :                  */
    4200         [ +  + ]:          12 :                 if (element_type == RECORDOID)
    4201                 :             :                 {
    4202                 :           3 :                         MemoryContext oldcontext;
    4203                 :           3 :                         TypeCacheEntry *record_typentry;
    4204                 :             : 
    4205                 :           3 :                         oldcontext = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
    4206                 :             : 
    4207                 :             :                         /*
    4208                 :             :                          * Make fake type cache entry structure.  Note that we can't just
    4209                 :             :                          * modify typentry, since that points directly into the type
    4210                 :             :                          * cache.
    4211                 :             :                          */
    4212                 :           3 :                         record_typentry = palloc0_object(TypeCacheEntry);
    4213                 :           3 :                         record_typentry->type_id = element_type;
    4214                 :             : 
    4215                 :             :                         /* fill in what we need below */
    4216                 :           3 :                         record_typentry->typlen = typentry->typlen;
    4217                 :           3 :                         record_typentry->typbyval = typentry->typbyval;
    4218                 :           3 :                         record_typentry->typalign = typentry->typalign;
    4219                 :           3 :                         fmgr_info(F_HASH_RECORD, &record_typentry->hash_proc_finfo);
    4220                 :             : 
    4221                 :           3 :                         MemoryContextSwitchTo(oldcontext);
    4222                 :             : 
    4223                 :           3 :                         typentry = record_typentry;
    4224                 :           3 :                 }
    4225                 :             : 
    4226                 :          12 :                 fcinfo->flinfo->fn_extra = typentry;
    4227                 :          12 :         }
    4228                 :             : 
    4229                 :        5881 :         typlen = typentry->typlen;
    4230                 :        5881 :         typbyval = typentry->typbyval;
    4231                 :        5881 :         typalign = typentry->typalign;
    4232                 :             : 
    4233                 :             :         /*
    4234                 :             :          * apply the hash function to each array element.
    4235                 :             :          */
    4236                 :        5881 :         InitFunctionCallInfoData(*locfcinfo, &typentry->hash_proc_finfo, 1,
    4237                 :             :                                                          PG_GET_COLLATION(), NULL, NULL);
    4238                 :             : 
    4239                 :             :         /* Loop over source data */
    4240                 :        5881 :         nitems = ArrayGetNItems(ndims, dims);
    4241                 :        5881 :         array_iter_setup(&iter, array);
    4242                 :             : 
    4243         [ +  + ]:       17682 :         for (i = 0; i < nitems; i++)
    4244                 :             :         {
    4245                 :       11801 :                 Datum           elt;
    4246                 :       11801 :                 bool            isnull;
    4247                 :       11801 :                 uint32          elthash;
    4248                 :             : 
    4249                 :             :                 /* Get element, checking for NULL */
    4250                 :       11801 :                 elt = array_iter_next(&iter, &isnull, i, typlen, typbyval, typalign);
    4251                 :             : 
    4252         [ -  + ]:       11801 :                 if (isnull)
    4253                 :             :                 {
    4254                 :             :                         /* Treat nulls as having hashvalue 0 */
    4255                 :           0 :                         elthash = 0;
    4256                 :           0 :                 }
    4257                 :             :                 else
    4258                 :             :                 {
    4259                 :             :                         /* Apply the hash function */
    4260                 :       11801 :                         locfcinfo->args[0].value = elt;
    4261                 :       11801 :                         locfcinfo->args[0].isnull = false;
    4262                 :       11801 :                         elthash = DatumGetUInt32(FunctionCallInvoke(locfcinfo));
    4263                 :             :                         /* We don't expect hash functions to return null */
    4264         [ -  + ]:       11801 :                         Assert(!locfcinfo->isnull);
    4265                 :             :                 }
    4266                 :             : 
    4267                 :             :                 /*
    4268                 :             :                  * Combine hash values of successive elements by multiplying the
    4269                 :             :                  * current value by 31 and adding on the new element's hash value.
    4270                 :             :                  *
    4271                 :             :                  * The result is a sum in which each element's hash value is
    4272                 :             :                  * multiplied by a different power of 31. This is modulo 2^32
    4273                 :             :                  * arithmetic, and the powers of 31 modulo 2^32 form a cyclic group of
    4274                 :             :                  * order 2^27. So for arrays of up to 2^27 elements, each element's
    4275                 :             :                  * hash value is multiplied by a different (odd) number, resulting in
    4276                 :             :                  * a good mixing of all the elements' hash values.
    4277                 :             :                  */
    4278                 :       11801 :                 result = (result << 5) - result + elthash;
    4279                 :       11801 :         }
    4280                 :             : 
    4281                 :             :         /* Avoid leaking memory when handed toasted input. */
    4282   [ +  +  +  + ]:        5881 :         AARR_FREE_IF_COPY(array, 0);
    4283                 :             : 
    4284                 :       11762 :         PG_RETURN_UINT32(result);
    4285                 :        5881 : }
    4286                 :             : 
    4287                 :             : /*
    4288                 :             :  * Returns 64-bit value by hashing a value to a 64-bit value, with a seed.
    4289                 :             :  * Otherwise, similar to hash_array.
    4290                 :             :  */
    4291                 :             : Datum
    4292                 :          24 : hash_array_extended(PG_FUNCTION_ARGS)
    4293                 :             : {
    4294                 :          24 :         LOCAL_FCINFO(locfcinfo, 2);
    4295                 :          24 :         AnyArrayType *array = PG_GETARG_ANY_ARRAY_P(0);
    4296                 :          24 :         uint64          seed = PG_GETARG_INT64(1);
    4297         [ +  - ]:          24 :         int                     ndims = AARR_NDIM(array);
    4298         [ +  - ]:          24 :         int                *dims = AARR_DIMS(array);
    4299         [ +  - ]:          24 :         Oid                     element_type = AARR_ELEMTYPE(array);
    4300                 :          24 :         uint64          result = 1;
    4301                 :          24 :         int                     nitems;
    4302                 :          24 :         TypeCacheEntry *typentry;
    4303                 :          24 :         int                     typlen;
    4304                 :          24 :         bool            typbyval;
    4305                 :          24 :         char            typalign;
    4306                 :          24 :         int                     i;
    4307                 :          24 :         array_iter      iter;
    4308                 :             : 
    4309                 :          24 :         typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
    4310   [ +  +  -  + ]:          24 :         if (typentry == NULL ||
    4311                 :          14 :                 typentry->type_id != element_type)
    4312                 :             :         {
    4313                 :          10 :                 typentry = lookup_type_cache(element_type,
    4314                 :             :                                                                          TYPECACHE_HASH_EXTENDED_PROC_FINFO);
    4315         [ +  + ]:          10 :                 if (!OidIsValid(typentry->hash_extended_proc_finfo.fn_oid))
    4316   [ +  -  +  - ]:           1 :                         ereport(ERROR,
    4317                 :             :                                         (errcode(ERRCODE_UNDEFINED_FUNCTION),
    4318                 :             :                                          errmsg("could not identify an extended hash function for type %s",
    4319                 :             :                                                         format_type_be(element_type))));
    4320                 :           9 :                 fcinfo->flinfo->fn_extra = typentry;
    4321                 :           9 :         }
    4322                 :          23 :         typlen = typentry->typlen;
    4323                 :          23 :         typbyval = typentry->typbyval;
    4324                 :          23 :         typalign = typentry->typalign;
    4325                 :             : 
    4326                 :          23 :         InitFunctionCallInfoData(*locfcinfo, &typentry->hash_extended_proc_finfo, 2,
    4327                 :             :                                                          PG_GET_COLLATION(), NULL, NULL);
    4328                 :             : 
    4329                 :             :         /* Loop over source data */
    4330                 :          23 :         nitems = ArrayGetNItems(ndims, dims);
    4331                 :          23 :         array_iter_setup(&iter, array);
    4332                 :             : 
    4333         [ +  + ]:          76 :         for (i = 0; i < nitems; i++)
    4334                 :             :         {
    4335                 :          53 :                 Datum           elt;
    4336                 :          53 :                 bool            isnull;
    4337                 :          53 :                 uint64          elthash;
    4338                 :             : 
    4339                 :             :                 /* Get element, checking for NULL */
    4340                 :          53 :                 elt = array_iter_next(&iter, &isnull, i, typlen, typbyval, typalign);
    4341                 :             : 
    4342         [ -  + ]:          53 :                 if (isnull)
    4343                 :             :                 {
    4344                 :           0 :                         elthash = 0;
    4345                 :           0 :                 }
    4346                 :             :                 else
    4347                 :             :                 {
    4348                 :             :                         /* Apply the hash function */
    4349                 :          53 :                         locfcinfo->args[0].value = elt;
    4350                 :          53 :                         locfcinfo->args[0].isnull = false;
    4351                 :          53 :                         locfcinfo->args[1].value = Int64GetDatum(seed);
    4352                 :          53 :                         locfcinfo->args[1].isnull = false;
    4353                 :          53 :                         elthash = DatumGetUInt64(FunctionCallInvoke(locfcinfo));
    4354                 :             :                         /* We don't expect hash functions to return null */
    4355         [ -  + ]:          53 :                         Assert(!locfcinfo->isnull);
    4356                 :             :                 }
    4357                 :             : 
    4358                 :          53 :                 result = (result << 5) - result + elthash;
    4359                 :          53 :         }
    4360                 :             : 
    4361   [ -  +  +  - ]:          23 :         AARR_FREE_IF_COPY(array, 0);
    4362                 :             : 
    4363                 :          46 :         PG_RETURN_UINT64(result);
    4364                 :          23 : }
    4365                 :             : 
    4366                 :             : 
    4367                 :             : /*-----------------------------------------------------------------------------
    4368                 :             :  * array overlap/containment comparisons
    4369                 :             :  *              These use the same methods of comparing array elements as array_eq.
    4370                 :             :  *              We consider only the elements of the arrays, ignoring dimensionality.
    4371                 :             :  *----------------------------------------------------------------------------
    4372                 :             :  */
    4373                 :             : 
    4374                 :             : /*
    4375                 :             :  * array_contain_compare :
    4376                 :             :  *                compares two arrays for overlap/containment
    4377                 :             :  *
    4378                 :             :  * When matchall is true, return true if all members of array1 are in array2.
    4379                 :             :  * When matchall is false, return true if any members of array1 are in array2.
    4380                 :             :  */
    4381                 :             : static bool
    4382                 :        3648 : array_contain_compare(AnyArrayType *array1, AnyArrayType *array2, Oid collation,
    4383                 :             :                                           bool matchall, void **fn_extra)
    4384                 :             : {
    4385                 :        3648 :         LOCAL_FCINFO(locfcinfo, 2);
    4386                 :        3648 :         bool            result = matchall;
    4387         [ +  + ]:        3648 :         Oid                     element_type = AARR_ELEMTYPE(array1);
    4388                 :        3648 :         TypeCacheEntry *typentry;
    4389                 :        3648 :         int                     nelems1;
    4390                 :        3648 :         Datum      *values2;
    4391                 :        3648 :         bool       *nulls2;
    4392                 :        3648 :         int                     nelems2;
    4393                 :        3648 :         int                     typlen;
    4394                 :        3648 :         bool            typbyval;
    4395                 :        3648 :         char            typalign;
    4396                 :        3648 :         int                     i;
    4397                 :        3648 :         int                     j;
    4398                 :        3648 :         array_iter      it1;
    4399                 :             : 
    4400   [ +  +  +  - ]:        3648 :         if (element_type != AARR_ELEMTYPE(array2))
    4401   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    4402                 :             :                                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    4403                 :             :                                  errmsg("cannot compare arrays of different element types")));
    4404                 :             : 
    4405                 :             :         /*
    4406                 :             :          * We arrange to look up the equality function only once per series of
    4407                 :             :          * calls, assuming the element type doesn't change underneath us.  The
    4408                 :             :          * typcache is used so that we have no memory leakage when being used as
    4409                 :             :          * an index support function.
    4410                 :             :          */
    4411                 :        3648 :         typentry = (TypeCacheEntry *) *fn_extra;
    4412   [ +  +  -  + ]:        3648 :         if (typentry == NULL ||
    4413                 :        3582 :                 typentry->type_id != element_type)
    4414                 :             :         {
    4415                 :          66 :                 typentry = lookup_type_cache(element_type,
    4416                 :             :                                                                          TYPECACHE_EQ_OPR_FINFO);
    4417         [ +  - ]:          66 :                 if (!OidIsValid(typentry->eq_opr_finfo.fn_oid))
    4418   [ #  #  #  # ]:           0 :                         ereport(ERROR,
    4419                 :             :                                         (errcode(ERRCODE_UNDEFINED_FUNCTION),
    4420                 :             :                                          errmsg("could not identify an equality operator for type %s",
    4421                 :             :                                                         format_type_be(element_type))));
    4422                 :          66 :                 *fn_extra = typentry;
    4423                 :          66 :         }
    4424                 :        3648 :         typlen = typentry->typlen;
    4425                 :        3648 :         typbyval = typentry->typbyval;
    4426                 :        3648 :         typalign = typentry->typalign;
    4427                 :             : 
    4428                 :             :         /*
    4429                 :             :          * Since we probably will need to scan array2 multiple times, it's
    4430                 :             :          * worthwhile to use deconstruct_array on it.  We scan array1 the hard way
    4431                 :             :          * however, since we very likely won't need to look at all of it.
    4432                 :             :          */
    4433         [ +  + ]:        3648 :         if (VARATT_IS_EXPANDED_HEADER(array2))
    4434                 :             :         {
    4435                 :             :                 /* This should be safe even if input is read-only */
    4436                 :         852 :                 deconstruct_expanded_array(&(array2->xpn));
    4437                 :         852 :                 values2 = array2->xpn.dvalues;
    4438                 :         852 :                 nulls2 = array2->xpn.dnulls;
    4439                 :         852 :                 nelems2 = array2->xpn.nelems;
    4440                 :         852 :         }
    4441                 :             :         else
    4442                 :        5592 :                 deconstruct_array((ArrayType *) array2,
    4443                 :        2796 :                                                   element_type, typlen, typbyval, typalign,
    4444                 :             :                                                   &values2, &nulls2, &nelems2);
    4445                 :             : 
    4446                 :             :         /*
    4447                 :             :          * Apply the comparison operator to each pair of array elements.
    4448                 :             :          */
    4449                 :        3648 :         InitFunctionCallInfoData(*locfcinfo, &typentry->eq_opr_finfo, 2,
    4450                 :             :                                                          collation, NULL, NULL);
    4451                 :             : 
    4452                 :             :         /* Loop over source data */
    4453   [ +  +  +  + ]:        3648 :         nelems1 = ArrayGetNItems(AARR_NDIM(array1), AARR_DIMS(array1));
    4454                 :        3648 :         array_iter_setup(&it1, array1);
    4455                 :             : 
    4456         [ +  + ]:       69958 :         for (i = 0; i < nelems1; i++)
    4457                 :             :         {
    4458                 :       67792 :                 Datum           elt1;
    4459                 :       67792 :                 bool            isnull1;
    4460                 :             : 
    4461                 :             :                 /* Get element, checking for NULL */
    4462                 :       67792 :                 elt1 = array_iter_next(&it1, &isnull1, i, typlen, typbyval, typalign);
    4463                 :             : 
    4464                 :             :                 /*
    4465                 :             :                  * We assume that the comparison operator is strict, so a NULL can't
    4466                 :             :                  * match anything.  XXX this diverges from the "NULL=NULL" behavior of
    4467                 :             :                  * array_eq, should we act like that?
    4468                 :             :                  */
    4469         [ +  + ]:       67792 :                 if (isnull1)
    4470                 :             :                 {
    4471         [ +  + ]:         220 :                         if (matchall)
    4472                 :             :                         {
    4473                 :         210 :                                 result = false;
    4474                 :         210 :                                 break;
    4475                 :             :                         }
    4476                 :          10 :                         continue;
    4477                 :             :                 }
    4478                 :             : 
    4479         [ +  + ]:     3069076 :                 for (j = 0; j < nelems2; j++)
    4480                 :             :                 {
    4481                 :     3062601 :                         Datum           elt2 = values2[j];
    4482         [ +  + ]:     3062601 :                         bool            isnull2 = nulls2 ? nulls2[j] : false;
    4483                 :     3062601 :                         bool            oprresult;
    4484                 :             : 
    4485         [ +  + ]:     3062601 :                         if (isnull2)
    4486                 :        1202 :                                 continue;               /* can't match */
    4487                 :             : 
    4488                 :             :                         /*
    4489                 :             :                          * Apply the operator to the element pair; treat NULL as false
    4490                 :             :                          */
    4491                 :     3061399 :                         locfcinfo->args[0].value = elt1;
    4492                 :     3061399 :                         locfcinfo->args[0].isnull = false;
    4493                 :     3061399 :                         locfcinfo->args[1].value = elt2;
    4494                 :     3061399 :                         locfcinfo->args[1].isnull = false;
    4495                 :     3061399 :                         locfcinfo->isnull = false;
    4496                 :     3061399 :                         oprresult = DatumGetBool(FunctionCallInvoke(locfcinfo));
    4497   [ +  -  +  + ]:     3061399 :                         if (!locfcinfo->isnull && oprresult)
    4498                 :       61097 :                                 break;
    4499      [ +  +  + ]:     3062601 :                 }
    4500                 :             : 
    4501         [ +  + ]:       67572 :                 if (j < nelems2)
    4502                 :             :                 {
    4503                 :             :                         /* found a match for elt1 */
    4504         [ +  + ]:       61097 :                         if (!matchall)
    4505                 :             :                         {
    4506                 :          38 :                                 result = true;
    4507                 :          38 :                                 break;
    4508                 :             :                         }
    4509                 :       61059 :                 }
    4510                 :             :                 else
    4511                 :             :                 {
    4512                 :             :                         /* no match for elt1 */
    4513         [ +  + ]:        6475 :                         if (matchall)
    4514                 :             :                         {
    4515                 :        1234 :                                 result = false;
    4516                 :        1234 :                                 break;
    4517                 :             :                         }
    4518                 :             :                 }
    4519      [ +  +  + ]:       67792 :         }
    4520                 :             : 
    4521                 :        7296 :         return result;
    4522                 :        3648 : }
    4523                 :             : 
    4524                 :             : Datum
    4525                 :        1020 : arrayoverlap(PG_FUNCTION_ARGS)
    4526                 :             : {
    4527                 :        1020 :         AnyArrayType *array1 = PG_GETARG_ANY_ARRAY_P(0);
    4528                 :        1020 :         AnyArrayType *array2 = PG_GETARG_ANY_ARRAY_P(1);
    4529                 :        1020 :         Oid                     collation = PG_GET_COLLATION();
    4530                 :        1020 :         bool            result;
    4531                 :             : 
    4532                 :        2040 :         result = array_contain_compare(array1, array2, collation, false,
    4533                 :        1020 :                                                                    &fcinfo->flinfo->fn_extra);
    4534                 :             : 
    4535                 :             :         /* Avoid leaking memory when handed toasted input. */
    4536   [ -  +  +  + ]:        1020 :         AARR_FREE_IF_COPY(array1, 0);
    4537   [ -  +  +  - ]:        1020 :         AARR_FREE_IF_COPY(array2, 1);
    4538                 :             : 
    4539                 :        2040 :         PG_RETURN_BOOL(result);
    4540                 :        1020 : }
    4541                 :             : 
    4542                 :             : Datum
    4543                 :        1542 : arraycontains(PG_FUNCTION_ARGS)
    4544                 :             : {
    4545                 :        1542 :         AnyArrayType *array1 = PG_GETARG_ANY_ARRAY_P(0);
    4546                 :        1542 :         AnyArrayType *array2 = PG_GETARG_ANY_ARRAY_P(1);
    4547                 :        1542 :         Oid                     collation = PG_GET_COLLATION();
    4548                 :        1542 :         bool            result;
    4549                 :             : 
    4550                 :        3084 :         result = array_contain_compare(array2, array1, collation, true,
    4551                 :        1542 :                                                                    &fcinfo->flinfo->fn_extra);
    4552                 :             : 
    4553                 :             :         /* Avoid leaking memory when handed toasted input. */
    4554   [ +  +  +  + ]:        1542 :         AARR_FREE_IF_COPY(array1, 0);
    4555   [ +  +  +  - ]:        1542 :         AARR_FREE_IF_COPY(array2, 1);
    4556                 :             : 
    4557                 :        3084 :         PG_RETURN_BOOL(result);
    4558                 :        1542 : }
    4559                 :             : 
    4560                 :             : Datum
    4561                 :        1086 : arraycontained(PG_FUNCTION_ARGS)
    4562                 :             : {
    4563                 :        1086 :         AnyArrayType *array1 = PG_GETARG_ANY_ARRAY_P(0);
    4564                 :        1086 :         AnyArrayType *array2 = PG_GETARG_ANY_ARRAY_P(1);
    4565                 :        1086 :         Oid                     collation = PG_GET_COLLATION();
    4566                 :        1086 :         bool            result;
    4567                 :             : 
    4568                 :        2172 :         result = array_contain_compare(array1, array2, collation, true,
    4569                 :        1086 :                                                                    &fcinfo->flinfo->fn_extra);
    4570                 :             : 
    4571                 :             :         /* Avoid leaking memory when handed toasted input. */
    4572   [ +  +  +  + ]:        1086 :         AARR_FREE_IF_COPY(array1, 0);
    4573   [ +  +  +  - ]:        1086 :         AARR_FREE_IF_COPY(array2, 1);
    4574                 :             : 
    4575                 :        2172 :         PG_RETURN_BOOL(result);
    4576                 :        1086 : }
    4577                 :             : 
    4578                 :             : 
    4579                 :             : /*-----------------------------------------------------------------------------
    4580                 :             :  * Array iteration functions
    4581                 :             :  *              These functions are used to iterate efficiently through arrays
    4582                 :             :  *-----------------------------------------------------------------------------
    4583                 :             :  */
    4584                 :             : 
    4585                 :             : /*
    4586                 :             :  * array_create_iterator --- set up to iterate through an array
    4587                 :             :  *
    4588                 :             :  * If slice_ndim is zero, we will iterate element-by-element; the returned
    4589                 :             :  * datums are of the array's element type.
    4590                 :             :  *
    4591                 :             :  * If slice_ndim is 1..ARR_NDIM(arr), we will iterate by slices: the
    4592                 :             :  * returned datums are of the same array type as 'arr', but of size
    4593                 :             :  * equal to the rightmost N dimensions of 'arr'.
    4594                 :             :  *
    4595                 :             :  * The passed-in array must remain valid for the lifetime of the iterator.
    4596                 :             :  */
    4597                 :             : ArrayIterator
    4598                 :          52 : array_create_iterator(ArrayType *arr, int slice_ndim, ArrayMetaState *mstate)
    4599                 :             : {
    4600                 :          52 :         ArrayIterator iterator = palloc0_object(ArrayIteratorData);
    4601                 :             : 
    4602                 :             :         /*
    4603                 :             :          * Sanity-check inputs --- caller should have got this right already
    4604                 :             :          */
    4605         [ +  - ]:          52 :         Assert(arr);
    4606         [ +  - ]:          52 :         if (slice_ndim < 0 || slice_ndim > ARR_NDIM(arr))
    4607   [ #  #  #  # ]:           0 :                 elog(ERROR, "invalid arguments to array_create_iterator");
    4608                 :             : 
    4609                 :             :         /*
    4610                 :             :          * Remember basic info about the array and its element type
    4611                 :             :          */
    4612                 :          52 :         iterator->arr = arr;
    4613         [ +  + ]:          52 :         iterator->nullbitmap = ARR_NULLBITMAP(arr);
    4614                 :          52 :         iterator->nitems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));
    4615                 :             : 
    4616         [ +  + ]:          52 :         if (mstate != NULL)
    4617                 :             :         {
    4618         [ +  - ]:          40 :                 Assert(mstate->element_type == ARR_ELEMTYPE(arr));
    4619                 :             : 
    4620                 :          40 :                 iterator->typlen = mstate->typlen;
    4621                 :          40 :                 iterator->typbyval = mstate->typbyval;
    4622                 :          40 :                 iterator->typalign = mstate->typalign;
    4623                 :          40 :         }
    4624                 :             :         else
    4625                 :          24 :                 get_typlenbyvalalign(ARR_ELEMTYPE(arr),
    4626                 :          12 :                                                          &iterator->typlen,
    4627                 :          12 :                                                          &iterator->typbyval,
    4628                 :          12 :                                                          &iterator->typalign);
    4629                 :             : 
    4630                 :             :         /*
    4631                 :             :          * Remember the slicing parameters.
    4632                 :             :          */
    4633                 :          52 :         iterator->slice_ndim = slice_ndim;
    4634                 :             : 
    4635         [ +  + ]:          52 :         if (slice_ndim > 0)
    4636                 :             :         {
    4637                 :             :                 /*
    4638                 :             :                  * Get pointers into the array's dims and lbound arrays to represent
    4639                 :             :                  * the dims/lbound arrays of a slice.  These are the same as the
    4640                 :             :                  * rightmost N dimensions of the array.
    4641                 :             :                  */
    4642                 :          13 :                 iterator->slice_dims = ARR_DIMS(arr) + ARR_NDIM(arr) - slice_ndim;
    4643                 :          13 :                 iterator->slice_lbound = ARR_LBOUND(arr) + ARR_NDIM(arr) - slice_ndim;
    4644                 :             : 
    4645                 :             :                 /*
    4646                 :             :                  * Compute number of elements in a slice.
    4647                 :             :                  */
    4648                 :          26 :                 iterator->slice_len = ArrayGetNItems(slice_ndim,
    4649                 :          13 :                                                                                          iterator->slice_dims);
    4650                 :             : 
    4651                 :             :                 /*
    4652                 :             :                  * Create workspace for building sub-arrays.
    4653                 :             :                  */
    4654                 :          13 :                 iterator->slice_values = (Datum *)
    4655                 :          13 :                         palloc(iterator->slice_len * sizeof(Datum));
    4656                 :          13 :                 iterator->slice_nulls = (bool *)
    4657                 :          13 :                         palloc(iterator->slice_len * sizeof(bool));
    4658                 :          13 :         }
    4659                 :             : 
    4660                 :             :         /*
    4661                 :             :          * Initialize our data pointer and linear element number.  These will
    4662                 :             :          * advance through the array during array_iterate().
    4663                 :             :          */
    4664         [ +  + ]:          52 :         iterator->data_ptr = ARR_DATA_PTR(arr);
    4665                 :          52 :         iterator->current_item = 0;
    4666                 :             : 
    4667                 :         104 :         return iterator;
    4668                 :          52 : }
    4669                 :             : 
    4670                 :             : /*
    4671                 :             :  * Iterate through the array referenced by 'iterator'.
    4672                 :             :  *
    4673                 :             :  * As long as there is another element (or slice), return it into
    4674                 :             :  * *value / *isnull, and return true.  Return false when no more data.
    4675                 :             :  */
    4676                 :             : bool
    4677                 :         345 : array_iterate(ArrayIterator iterator, Datum *value, bool *isnull)
    4678                 :             : {
    4679                 :             :         /* Done if we have reached the end of the array */
    4680         [ +  + ]:         345 :         if (iterator->current_item >= iterator->nitems)
    4681                 :          40 :                 return false;
    4682                 :             : 
    4683         [ +  + ]:         305 :         if (iterator->slice_ndim == 0)
    4684                 :             :         {
    4685                 :             :                 /*
    4686                 :             :                  * Scalar case: return one element.
    4687                 :             :                  */
    4688         [ +  + ]:         279 :                 if (array_get_isnull(iterator->nullbitmap, iterator->current_item++))
    4689                 :             :                 {
    4690                 :          11 :                         *isnull = true;
    4691                 :          11 :                         *value = (Datum) 0;
    4692                 :          11 :                 }
    4693                 :             :                 else
    4694                 :             :                 {
    4695                 :             :                         /* non-NULL, so fetch the individual Datum to return */
    4696                 :         268 :                         char       *p = iterator->data_ptr;
    4697                 :             : 
    4698                 :         268 :                         *isnull = false;
    4699                 :         268 :                         *value = fetch_att(p, iterator->typbyval, iterator->typlen);
    4700                 :             : 
    4701                 :             :                         /* Move our data pointer forward to the next element */
    4702   [ +  +  -  +  :         268 :                         p = att_addlength_pointer(p, iterator->typlen, p);
                   #  # ]
    4703   [ +  +  -  +  :         268 :                         p = (char *) att_align_nominal(p, iterator->typalign);
             +  -  #  # ]
    4704                 :         268 :                         iterator->data_ptr = p;
    4705                 :         268 :                 }
    4706                 :         279 :         }
    4707                 :             :         else
    4708                 :             :         {
    4709                 :             :                 /*
    4710                 :             :                  * Slice case: build and return an array of the requested size.
    4711                 :             :                  */
    4712                 :          26 :                 ArrayType  *result;
    4713                 :          26 :                 Datum      *values = iterator->slice_values;
    4714                 :          26 :                 bool       *nulls = iterator->slice_nulls;
    4715                 :          26 :                 char       *p = iterator->data_ptr;
    4716                 :          26 :                 int                     i;
    4717                 :             : 
    4718         [ +  + ]:          83 :                 for (i = 0; i < iterator->slice_len; i++)
    4719                 :             :                 {
    4720   [ -  +  -  + ]:         114 :                         if (array_get_isnull(iterator->nullbitmap,
    4721                 :          57 :                                                                  iterator->current_item++))
    4722                 :             :                         {
    4723                 :           0 :                                 nulls[i] = true;
    4724                 :           0 :                                 values[i] = (Datum) 0;
    4725                 :           0 :                         }
    4726                 :             :                         else
    4727                 :             :                         {
    4728                 :          57 :                                 nulls[i] = false;
    4729                 :          57 :                                 values[i] = fetch_att(p, iterator->typbyval, iterator->typlen);
    4730                 :             : 
    4731                 :             :                                 /* Move our data pointer forward to the next element */
    4732   [ +  +  -  +  :          57 :                                 p = att_addlength_pointer(p, iterator->typlen, p);
                   #  # ]
    4733   [ +  +  -  +  :          57 :                                 p = (char *) att_align_nominal(p, iterator->typalign);
             +  -  #  # ]
    4734                 :             :                         }
    4735                 :          57 :                 }
    4736                 :             : 
    4737                 :          26 :                 iterator->data_ptr = p;
    4738                 :             : 
    4739                 :          52 :                 result = construct_md_array(values,
    4740                 :          26 :                                                                         nulls,
    4741                 :          26 :                                                                         iterator->slice_ndim,
    4742                 :          26 :                                                                         iterator->slice_dims,
    4743                 :          26 :                                                                         iterator->slice_lbound,
    4744                 :          26 :                                                                         ARR_ELEMTYPE(iterator->arr),
    4745                 :          26 :                                                                         iterator->typlen,
    4746                 :          26 :                                                                         iterator->typbyval,
    4747                 :          26 :                                                                         iterator->typalign);
    4748                 :             : 
    4749                 :          26 :                 *isnull = false;
    4750                 :          26 :                 *value = PointerGetDatum(result);
    4751                 :          26 :         }
    4752                 :             : 
    4753                 :         305 :         return true;
    4754                 :         345 : }
    4755                 :             : 
    4756                 :             : /*
    4757                 :             :  * Release an ArrayIterator data structure
    4758                 :             :  */
    4759                 :             : void
    4760                 :          40 : array_free_iterator(ArrayIterator iterator)
    4761                 :             : {
    4762         [ +  + ]:          40 :         if (iterator->slice_ndim > 0)
    4763                 :             :         {
    4764                 :           7 :                 pfree(iterator->slice_values);
    4765                 :           7 :                 pfree(iterator->slice_nulls);
    4766                 :           7 :         }
    4767                 :          40 :         pfree(iterator);
    4768                 :          40 : }
    4769                 :             : 
    4770                 :             : 
    4771                 :             : /***************************************************************************/
    4772                 :             : /******************|              Support  Routines                       |*****************/
    4773                 :             : /***************************************************************************/
    4774                 :             : 
    4775                 :             : /*
    4776                 :             :  * Check whether a specific array element is NULL
    4777                 :             :  *
    4778                 :             :  * nullbitmap: pointer to array's null bitmap (NULL if none)
    4779                 :             :  * offset: 0-based linear element number of array element
    4780                 :             :  */
    4781                 :             : static bool
    4782                 :       39839 : array_get_isnull(const bits8 *nullbitmap, int offset)
    4783                 :             : {
    4784         [ +  + ]:       39839 :         if (nullbitmap == NULL)
    4785                 :       39701 :                 return false;                   /* assume not null */
    4786         [ +  + ]:         138 :         if (nullbitmap[offset / 8] & (1 << (offset % 8)))
    4787                 :         109 :                 return false;                   /* not null */
    4788                 :          29 :         return true;
    4789                 :       39839 : }
    4790                 :             : 
    4791                 :             : /*
    4792                 :             :  * Set a specific array element's null-bitmap entry
    4793                 :             :  *
    4794                 :             :  * nullbitmap: pointer to array's null bitmap (mustn't be NULL)
    4795                 :             :  * offset: 0-based linear element number of array element
    4796                 :             :  * isNull: null status to set
    4797                 :             :  */
    4798                 :             : static void
    4799                 :          22 : array_set_isnull(bits8 *nullbitmap, int offset, bool isNull)
    4800                 :             : {
    4801                 :          22 :         int                     bitmask;
    4802                 :             : 
    4803                 :          22 :         nullbitmap += offset / 8;
    4804                 :          22 :         bitmask = 1 << (offset % 8);
    4805         [ +  + ]:          22 :         if (isNull)
    4806                 :           3 :                 *nullbitmap &= ~bitmask;
    4807                 :             :         else
    4808                 :          19 :                 *nullbitmap |= bitmask;
    4809                 :          22 : }
    4810                 :             : 
    4811                 :             : /*
    4812                 :             :  * Fetch array element at pointer, converted correctly to a Datum
    4813                 :             :  *
    4814                 :             :  * Caller must have handled case of NULL element
    4815                 :             :  */
    4816                 :             : static Datum
    4817                 :       39393 : ArrayCast(char *value, bool byval, int len)
    4818                 :             : {
    4819                 :       39393 :         return fetch_att(value, byval, len);
    4820                 :             : }
    4821                 :             : 
    4822                 :             : /*
    4823                 :             :  * Copy datum to *dest and return total space used (including align padding)
    4824                 :             :  *
    4825                 :             :  * Caller must have handled case of NULL element
    4826                 :             :  */
    4827                 :             : static int
    4828                 :     1274421 : ArrayCastAndSet(Datum src,
    4829                 :             :                                 int typlen,
    4830                 :             :                                 bool typbyval,
    4831                 :             :                                 char typalign,
    4832                 :             :                                 char *dest)
    4833                 :             : {
    4834                 :     1274421 :         int                     inc;
    4835                 :             : 
    4836         [ +  + ]:     1274421 :         if (typlen > 0)
    4837                 :             :         {
    4838         [ +  + ]:     1132265 :                 if (typbyval)
    4839                 :      527091 :                         store_att_byval(dest, src, typlen);
    4840                 :             :                 else
    4841                 :      605174 :                         memmove(dest, DatumGetPointer(src), typlen);
    4842   [ +  +  +  +  :     1132265 :                 inc = att_align_nominal(typlen, typalign);
             +  +  +  - ]
    4843                 :     1132265 :         }
    4844                 :             :         else
    4845                 :             :         {
    4846         [ +  - ]:      142156 :                 Assert(!typbyval);
    4847   [ -  +  +  +  :      142156 :                 inc = att_addlength_datum(0, typlen, src);
                   +  - ]
    4848                 :      142156 :                 memmove(dest, DatumGetPointer(src), inc);
    4849   [ +  +  +  +  :      142156 :                 inc = att_align_nominal(inc, typalign);
             +  -  #  # ]
    4850                 :             :         }
    4851                 :             : 
    4852                 :     2548842 :         return inc;
    4853                 :     1274421 : }
    4854                 :             : 
    4855                 :             : /*
    4856                 :             :  * Advance ptr over nitems array elements
    4857                 :             :  *
    4858                 :             :  * ptr: starting location in array
    4859                 :             :  * offset: 0-based linear element number of first element (the one at *ptr)
    4860                 :             :  * nullbitmap: start of array's null bitmap, or NULL if none
    4861                 :             :  * nitems: number of array elements to advance over (>= 0)
    4862                 :             :  * typlen, typbyval, typalign: storage parameters of array element datatype
    4863                 :             :  *
    4864                 :             :  * It is caller's responsibility to ensure that nitems is within range
    4865                 :             :  */
    4866                 :             : static char *
    4867                 :       39797 : array_seek(char *ptr, int offset, bits8 *nullbitmap, int nitems,
    4868                 :             :                    int typlen, bool typbyval, char typalign)
    4869                 :             : {
    4870                 :       39797 :         int                     bitmask;
    4871                 :       39797 :         int                     i;
    4872                 :             : 
    4873                 :             :         /* easy if fixed-size elements and no NULLs */
    4874   [ +  +  +  + ]:       39797 :         if (typlen > 0 && !nullbitmap)
    4875   [ +  +  +  +  :       32736 :                 return ptr + nitems * ((Size) att_align_nominal(typlen, typalign));
             +  +  +  - ]
    4876                 :             : 
    4877                 :             :         /* seems worth having separate loops for NULL and no-NULLs cases */
    4878         [ +  + ]:        7061 :         if (nullbitmap)
    4879                 :             :         {
    4880                 :         100 :                 nullbitmap += offset / 8;
    4881                 :         100 :                 bitmask = 1 << (offset % 8);
    4882                 :             : 
    4883         [ +  + ]:         308 :                 for (i = 0; i < nitems; i++)
    4884                 :             :                 {
    4885         [ +  + ]:         208 :                         if (*nullbitmap & bitmask)
    4886                 :             :                         {
    4887   [ +  +  -  +  :         148 :                                 ptr = att_addlength_pointer(ptr, typlen, ptr);
                   #  # ]
    4888   [ +  +  +  -  :         148 :                                 ptr = (char *) att_align_nominal(ptr, typalign);
             #  #  #  # ]
    4889                 :         148 :                         }
    4890                 :         208 :                         bitmask <<= 1;
    4891         [ +  + ]:         208 :                         if (bitmask == 0x100)
    4892                 :             :                         {
    4893                 :           8 :                                 nullbitmap++;
    4894                 :           8 :                                 bitmask = 1;
    4895                 :           8 :                         }
    4896                 :         208 :                 }
    4897                 :         100 :         }
    4898                 :             :         else
    4899                 :             :         {
    4900         [ +  + ]:       19620 :                 for (i = 0; i < nitems; i++)
    4901                 :             :                 {
    4902   [ -  +  -  +  :       12659 :                         ptr = att_addlength_pointer(ptr, typlen, ptr);
                   #  # ]
    4903   [ +  +  -  +  :       12659 :                         ptr = (char *) att_align_nominal(ptr, typalign);
             +  -  #  # ]
    4904                 :       12659 :                 }
    4905                 :             :         }
    4906                 :        7061 :         return ptr;
    4907                 :       39797 : }
    4908                 :             : 
    4909                 :             : /*
    4910                 :             :  * Compute total size of the nitems array elements starting at *ptr
    4911                 :             :  *
    4912                 :             :  * Parameters same as for array_seek
    4913                 :             :  */
    4914                 :             : static int
    4915                 :         272 : array_nelems_size(char *ptr, int offset, bits8 *nullbitmap, int nitems,
    4916                 :             :                                   int typlen, bool typbyval, char typalign)
    4917                 :             : {
    4918                 :         816 :         return array_seek(ptr, offset, nullbitmap, nitems,
    4919                 :         544 :                                           typlen, typbyval, typalign) - ptr;
    4920                 :             : }
    4921                 :             : 
    4922                 :             : /*
    4923                 :             :  * Copy nitems array elements from srcptr to destptr
    4924                 :             :  *
    4925                 :             :  * destptr: starting destination location (must be enough room!)
    4926                 :             :  * nitems: number of array elements to copy (>= 0)
    4927                 :             :  * srcptr: starting location in source array
    4928                 :             :  * offset: 0-based linear element number of first element (the one at *srcptr)
    4929                 :             :  * nullbitmap: start of source array's null bitmap, or NULL if none
    4930                 :             :  * typlen, typbyval, typalign: storage parameters of array element datatype
    4931                 :             :  *
    4932                 :             :  * Returns number of bytes copied
    4933                 :             :  *
    4934                 :             :  * NB: this does not take care of setting up the destination's null bitmap!
    4935                 :             :  */
    4936                 :             : static int
    4937                 :         195 : array_copy(char *destptr, int nitems,
    4938                 :             :                    char *srcptr, int offset, bits8 *nullbitmap,
    4939                 :             :                    int typlen, bool typbyval, char typalign)
    4940                 :             : {
    4941                 :         195 :         int                     numbytes;
    4942                 :             : 
    4943                 :         390 :         numbytes = array_nelems_size(srcptr, offset, nullbitmap, nitems,
    4944                 :         195 :                                                                  typlen, typbyval, typalign);
    4945                 :         195 :         memcpy(destptr, srcptr, numbytes);
    4946                 :         390 :         return numbytes;
    4947                 :         195 : }
    4948                 :             : 
    4949                 :             : /*
    4950                 :             :  * Copy nitems null-bitmap bits from source to destination
    4951                 :             :  *
    4952                 :             :  * destbitmap: start of destination array's null bitmap (mustn't be NULL)
    4953                 :             :  * destoffset: 0-based linear element number of first dest element
    4954                 :             :  * srcbitmap: start of source array's null bitmap, or NULL if none
    4955                 :             :  * srcoffset: 0-based linear element number of first source element
    4956                 :             :  * nitems: number of bits to copy (>= 0)
    4957                 :             :  *
    4958                 :             :  * If srcbitmap is NULL then we assume the source is all-non-NULL and
    4959                 :             :  * fill 1's into the destination bitmap.  Note that only the specified
    4960                 :             :  * bits in the destination map are changed, not any before or after.
    4961                 :             :  *
    4962                 :             :  * Note: this could certainly be optimized using standard bitblt methods.
    4963                 :             :  * However, it's not clear that the typical Postgres array has enough elements
    4964                 :             :  * to make it worth worrying too much.  For the moment, KISS.
    4965                 :             :  */
    4966                 :             : void
    4967                 :        5138 : array_bitmap_copy(bits8 *destbitmap, int destoffset,
    4968                 :             :                                   const bits8 *srcbitmap, int srcoffset,
    4969                 :             :                                   int nitems)
    4970                 :             : {
    4971                 :        5138 :         int                     destbitmask,
    4972                 :             :                                 destbitval,
    4973                 :             :                                 srcbitmask,
    4974                 :             :                                 srcbitval;
    4975                 :             : 
    4976         [ +  - ]:        5138 :         Assert(destbitmap);
    4977         [ +  + ]:        5138 :         if (nitems <= 0)
    4978                 :          27 :                 return;                                 /* don't risk fetch off end of memory */
    4979                 :        5111 :         destbitmap += destoffset / 8;
    4980                 :        5111 :         destbitmask = 1 << (destoffset % 8);
    4981                 :        5111 :         destbitval = *destbitmap;
    4982         [ +  + ]:        5111 :         if (srcbitmap)
    4983                 :             :         {
    4984                 :        2601 :                 srcbitmap += srcoffset / 8;
    4985                 :        2601 :                 srcbitmask = 1 << (srcoffset % 8);
    4986                 :        2601 :                 srcbitval = *srcbitmap;
    4987         [ +  + ]:       12096 :                 while (nitems-- > 0)
    4988                 :             :                 {
    4989         [ +  + ]:        9495 :                         if (srcbitval & srcbitmask)
    4990                 :        3544 :                                 destbitval |= destbitmask;
    4991                 :             :                         else
    4992                 :        5951 :                                 destbitval &= ~destbitmask;
    4993                 :        9495 :                         destbitmask <<= 1;
    4994         [ +  + ]:        9495 :                         if (destbitmask == 0x100)
    4995                 :             :                         {
    4996                 :        1134 :                                 *destbitmap++ = destbitval;
    4997                 :        1134 :                                 destbitmask = 1;
    4998         [ +  + ]:        1134 :                                 if (nitems > 0)
    4999                 :         848 :                                         destbitval = *destbitmap;
    5000                 :        1134 :                         }
    5001                 :        9495 :                         srcbitmask <<= 1;
    5002         [ +  + ]:        9495 :                         if (srcbitmask == 0x100)
    5003                 :             :                         {
    5004                 :         845 :                                 srcbitmap++;
    5005                 :         845 :                                 srcbitmask = 1;
    5006         [ +  + ]:         845 :                                 if (nitems > 0)
    5007                 :         838 :                                         srcbitval = *srcbitmap;
    5008                 :         845 :                         }
    5009                 :             :                 }
    5010         [ +  + ]:        2601 :                 if (destbitmask != 1)
    5011                 :        2315 :                         *destbitmap = destbitval;
    5012                 :        2601 :         }
    5013                 :             :         else
    5014                 :             :         {
    5015         [ +  + ]:        5038 :                 while (nitems-- > 0)
    5016                 :             :                 {
    5017                 :        2528 :                         destbitval |= destbitmask;
    5018                 :        2528 :                         destbitmask <<= 1;
    5019         [ +  + ]:        2528 :                         if (destbitmask == 0x100)
    5020                 :             :                         {
    5021                 :         336 :                                 *destbitmap++ = destbitval;
    5022                 :         336 :                                 destbitmask = 1;
    5023         [ -  + ]:         336 :                                 if (nitems > 0)
    5024                 :           0 :                                         destbitval = *destbitmap;
    5025                 :         336 :                         }
    5026                 :             :                 }
    5027         [ +  + ]:        2510 :                 if (destbitmask != 1)
    5028                 :        2174 :                         *destbitmap = destbitval;
    5029                 :             :         }
    5030         [ -  + ]:        5138 : }
    5031                 :             : 
    5032                 :             : /*
    5033                 :             :  * Compute space needed for a slice of an array
    5034                 :             :  *
    5035                 :             :  * We assume the caller has verified that the slice coordinates are valid.
    5036                 :             :  */
    5037                 :             : static int
    5038                 :          51 : array_slice_size(char *arraydataptr, bits8 *arraynullsptr,
    5039                 :             :                                  int ndim, int *dim, int *lb,
    5040                 :             :                                  int *st, int *endp,
    5041                 :             :                                  int typlen, bool typbyval, char typalign)
    5042                 :             : {
    5043                 :          51 :         int                     src_offset,
    5044                 :             :                                 span[MAXDIM],
    5045                 :             :                                 prod[MAXDIM],
    5046                 :             :                                 dist[MAXDIM],
    5047                 :             :                                 indx[MAXDIM];
    5048                 :          51 :         char       *ptr;
    5049                 :          51 :         int                     i,
    5050                 :             :                                 j,
    5051                 :             :                                 inc;
    5052                 :          51 :         int                     count = 0;
    5053                 :             : 
    5054                 :          51 :         mda_get_range(ndim, span, st, endp);
    5055                 :             : 
    5056                 :             :         /* Pretty easy for fixed element length without nulls ... */
    5057   [ +  +  +  + ]:          51 :         if (typlen > 0 && !arraynullsptr)
    5058   [ +  +  +  +  :          38 :                 return ArrayGetNItems(ndim, span) * att_align_nominal(typlen, typalign);
             +  +  +  - ]
    5059                 :             : 
    5060                 :             :         /* Else gotta do it the hard way */
    5061                 :          13 :         src_offset = ArrayGetOffset(ndim, dim, lb, st);
    5062                 :          26 :         ptr = array_seek(arraydataptr, 0, arraynullsptr, src_offset,
    5063                 :          13 :                                          typlen, typbyval, typalign);
    5064                 :          13 :         mda_get_prod(ndim, dim, prod);
    5065                 :          13 :         mda_get_offset_values(ndim, dist, prod, span);
    5066         [ +  + ]:          33 :         for (i = 0; i < ndim; i++)
    5067                 :          20 :                 indx[i] = 0;
    5068                 :          13 :         j = ndim - 1;
    5069                 :          13 :         do
    5070                 :             :         {
    5071         [ +  - ]:          43 :                 if (dist[j])
    5072                 :             :                 {
    5073                 :           0 :                         ptr = array_seek(ptr, src_offset, arraynullsptr, dist[j],
    5074                 :           0 :                                                          typlen, typbyval, typalign);
    5075                 :           0 :                         src_offset += dist[j];
    5076                 :           0 :                 }
    5077         [ +  + ]:          43 :                 if (!array_get_isnull(arraynullsptr, src_offset))
    5078                 :             :                 {
    5079   [ +  +  -  +  :          41 :                         inc = att_addlength_pointer(0, typlen, ptr);
                   #  # ]
    5080   [ +  +  +  -  :          41 :                         inc = att_align_nominal(inc, typalign);
             #  #  #  # ]
    5081                 :          41 :                         ptr += inc;
    5082                 :          41 :                         count += inc;
    5083                 :          41 :                 }
    5084                 :          43 :                 src_offset++;
    5085         [ +  + ]:          43 :         } while ((j = mda_next_tuple(ndim, indx, span)) != -1);
    5086                 :          13 :         return count;
    5087                 :          51 : }
    5088                 :             : 
    5089                 :             : /*
    5090                 :             :  * Extract a slice of an array into consecutive elements in the destination
    5091                 :             :  * array.
    5092                 :             :  *
    5093                 :             :  * We assume the caller has verified that the slice coordinates are valid,
    5094                 :             :  * allocated enough storage for the result, and initialized the header
    5095                 :             :  * of the new array.
    5096                 :             :  */
    5097                 :             : static void
    5098                 :          46 : array_extract_slice(ArrayType *newarray,
    5099                 :             :                                         int ndim,
    5100                 :             :                                         int *dim,
    5101                 :             :                                         int *lb,
    5102                 :             :                                         char *arraydataptr,
    5103                 :             :                                         bits8 *arraynullsptr,
    5104                 :             :                                         int *st,
    5105                 :             :                                         int *endp,
    5106                 :             :                                         int typlen,
    5107                 :             :                                         bool typbyval,
    5108                 :             :                                         char typalign)
    5109                 :             : {
    5110         [ +  + ]:          46 :         char       *destdataptr = ARR_DATA_PTR(newarray);
    5111         [ +  + ]:          46 :         bits8      *destnullsptr = ARR_NULLBITMAP(newarray);
    5112                 :          46 :         char       *srcdataptr;
    5113                 :          46 :         int                     src_offset,
    5114                 :             :                                 dest_offset,
    5115                 :             :                                 prod[MAXDIM],
    5116                 :             :                                 span[MAXDIM],
    5117                 :             :                                 dist[MAXDIM],
    5118                 :             :                                 indx[MAXDIM];
    5119                 :          46 :         int                     i,
    5120                 :             :                                 j,
    5121                 :             :                                 inc;
    5122                 :             : 
    5123                 :          46 :         src_offset = ArrayGetOffset(ndim, dim, lb, st);
    5124                 :          92 :         srcdataptr = array_seek(arraydataptr, 0, arraynullsptr, src_offset,
    5125                 :          46 :                                                         typlen, typbyval, typalign);
    5126                 :          46 :         mda_get_prod(ndim, dim, prod);
    5127                 :          46 :         mda_get_range(ndim, span, st, endp);
    5128                 :          46 :         mda_get_offset_values(ndim, dist, prod, span);
    5129         [ +  + ]:         116 :         for (i = 0; i < ndim; i++)
    5130                 :          70 :                 indx[i] = 0;
    5131                 :          46 :         dest_offset = 0;
    5132                 :          46 :         j = ndim - 1;
    5133                 :          46 :         do
    5134                 :             :         {
    5135         [ +  + ]:         169 :                 if (dist[j])
    5136                 :             :                 {
    5137                 :             :                         /* skip unwanted elements */
    5138                 :          10 :                         srcdataptr = array_seek(srcdataptr, src_offset, arraynullsptr,
    5139                 :           5 :                                                                         dist[j],
    5140                 :           5 :                                                                         typlen, typbyval, typalign);
    5141                 :           5 :                         src_offset += dist[j];
    5142                 :           5 :                 }
    5143                 :         338 :                 inc = array_copy(destdataptr, 1,
    5144                 :         169 :                                                  srcdataptr, src_offset, arraynullsptr,
    5145                 :         169 :                                                  typlen, typbyval, typalign);
    5146         [ +  + ]:         169 :                 if (destnullsptr)
    5147                 :          60 :                         array_bitmap_copy(destnullsptr, dest_offset,
    5148                 :          30 :                                                           arraynullsptr, src_offset,
    5149                 :             :                                                           1);
    5150                 :         169 :                 destdataptr += inc;
    5151                 :         169 :                 srcdataptr += inc;
    5152                 :         169 :                 src_offset++;
    5153                 :         169 :                 dest_offset++;
    5154         [ +  + ]:         169 :         } while ((j = mda_next_tuple(ndim, indx, span)) != -1);
    5155                 :          46 : }
    5156                 :             : 
    5157                 :             : /*
    5158                 :             :  * Insert a slice into an array.
    5159                 :             :  *
    5160                 :             :  * ndim/dim[]/lb[] are dimensions of the original array.  A new array with
    5161                 :             :  * those same dimensions is to be constructed.  destArray must already
    5162                 :             :  * have been allocated and its header initialized.
    5163                 :             :  *
    5164                 :             :  * st[]/endp[] identify the slice to be replaced.  Elements within the slice
    5165                 :             :  * volume are taken from consecutive elements of the srcArray; elements
    5166                 :             :  * outside it are copied from origArray.
    5167                 :             :  *
    5168                 :             :  * We assume the caller has verified that the slice coordinates are valid.
    5169                 :             :  */
    5170                 :             : static void
    5171                 :           5 : array_insert_slice(ArrayType *destArray,
    5172                 :             :                                    ArrayType *origArray,
    5173                 :             :                                    ArrayType *srcArray,
    5174                 :             :                                    int ndim,
    5175                 :             :                                    int *dim,
    5176                 :             :                                    int *lb,
    5177                 :             :                                    int *st,
    5178                 :             :                                    int *endp,
    5179                 :             :                                    int typlen,
    5180                 :             :                                    bool typbyval,
    5181                 :             :                                    char typalign)
    5182                 :             : {
    5183         [ -  + ]:           5 :         char       *destPtr = ARR_DATA_PTR(destArray);
    5184         [ -  + ]:           5 :         char       *origPtr = ARR_DATA_PTR(origArray);
    5185         [ -  + ]:           5 :         char       *srcPtr = ARR_DATA_PTR(srcArray);
    5186         [ -  + ]:           5 :         bits8      *destBitmap = ARR_NULLBITMAP(destArray);
    5187         [ -  + ]:           5 :         bits8      *origBitmap = ARR_NULLBITMAP(origArray);
    5188         [ -  + ]:           5 :         bits8      *srcBitmap = ARR_NULLBITMAP(srcArray);
    5189                 :          10 :         int                     orignitems = ArrayGetNItems(ARR_NDIM(origArray),
    5190                 :           5 :                                                                                         ARR_DIMS(origArray));
    5191                 :           5 :         int                     dest_offset,
    5192                 :             :                                 orig_offset,
    5193                 :             :                                 src_offset,
    5194                 :             :                                 prod[MAXDIM],
    5195                 :             :                                 span[MAXDIM],
    5196                 :             :                                 dist[MAXDIM],
    5197                 :             :                                 indx[MAXDIM];
    5198                 :           5 :         int                     i,
    5199                 :             :                                 j,
    5200                 :             :                                 inc;
    5201                 :             : 
    5202                 :           5 :         dest_offset = ArrayGetOffset(ndim, dim, lb, st);
    5203                 :             :         /* copy items before the slice start */
    5204                 :          10 :         inc = array_copy(destPtr, dest_offset,
    5205                 :           5 :                                          origPtr, 0, origBitmap,
    5206                 :           5 :                                          typlen, typbyval, typalign);
    5207                 :           5 :         destPtr += inc;
    5208                 :           5 :         origPtr += inc;
    5209         [ +  - ]:           5 :         if (destBitmap)
    5210                 :           0 :                 array_bitmap_copy(destBitmap, 0, origBitmap, 0, dest_offset);
    5211                 :           5 :         orig_offset = dest_offset;
    5212                 :           5 :         mda_get_prod(ndim, dim, prod);
    5213                 :           5 :         mda_get_range(ndim, span, st, endp);
    5214                 :           5 :         mda_get_offset_values(ndim, dist, prod, span);
    5215         [ +  + ]:          17 :         for (i = 0; i < ndim; i++)
    5216                 :          12 :                 indx[i] = 0;
    5217                 :           5 :         src_offset = 0;
    5218                 :           5 :         j = ndim - 1;
    5219                 :           5 :         do
    5220                 :             :         {
    5221                 :             :                 /* Copy/advance over elements between here and next part of slice */
    5222         [ +  + ]:          13 :                 if (dist[j])
    5223                 :             :                 {
    5224                 :           6 :                         inc = array_copy(destPtr, dist[j],
    5225                 :           3 :                                                          origPtr, orig_offset, origBitmap,
    5226                 :           3 :                                                          typlen, typbyval, typalign);
    5227                 :           3 :                         destPtr += inc;
    5228                 :           3 :                         origPtr += inc;
    5229         [ +  - ]:           3 :                         if (destBitmap)
    5230                 :           0 :                                 array_bitmap_copy(destBitmap, dest_offset,
    5231                 :           0 :                                                                   origBitmap, orig_offset,
    5232                 :           0 :                                                                   dist[j]);
    5233                 :           3 :                         dest_offset += dist[j];
    5234                 :           3 :                         orig_offset += dist[j];
    5235                 :           3 :                 }
    5236                 :             :                 /* Copy new element at this slice position */
    5237                 :          26 :                 inc = array_copy(destPtr, 1,
    5238                 :          13 :                                                  srcPtr, src_offset, srcBitmap,
    5239                 :          13 :                                                  typlen, typbyval, typalign);
    5240         [ +  - ]:          13 :                 if (destBitmap)
    5241                 :           0 :                         array_bitmap_copy(destBitmap, dest_offset,
    5242                 :           0 :                                                           srcBitmap, src_offset,
    5243                 :             :                                                           1);
    5244                 :          13 :                 destPtr += inc;
    5245                 :          13 :                 srcPtr += inc;
    5246                 :          13 :                 dest_offset++;
    5247                 :          13 :                 src_offset++;
    5248                 :             :                 /* Advance over old element at this slice position */
    5249                 :          26 :                 origPtr = array_seek(origPtr, orig_offset, origBitmap, 1,
    5250                 :          13 :                                                          typlen, typbyval, typalign);
    5251                 :          13 :                 orig_offset++;
    5252         [ +  + ]:          13 :         } while ((j = mda_next_tuple(ndim, indx, span)) != -1);
    5253                 :             : 
    5254                 :             :         /* don't miss any data at the end */
    5255                 :          10 :         array_copy(destPtr, orignitems - orig_offset,
    5256                 :           5 :                            origPtr, orig_offset, origBitmap,
    5257                 :           5 :                            typlen, typbyval, typalign);
    5258         [ +  - ]:           5 :         if (destBitmap)
    5259                 :           0 :                 array_bitmap_copy(destBitmap, dest_offset,
    5260                 :           0 :                                                   origBitmap, orig_offset,
    5261                 :           0 :                                                   orignitems - orig_offset);
    5262                 :           5 : }
    5263                 :             : 
    5264                 :             : /*
    5265                 :             :  * initArrayResult - initialize an empty ArrayBuildState
    5266                 :             :  *
    5267                 :             :  *      element_type is the array element type (must be a valid array element type)
    5268                 :             :  *      rcontext is where to keep working state
    5269                 :             :  *      subcontext is a flag determining whether to use a separate memory context
    5270                 :             :  *
    5271                 :             :  * Note: there are two common schemes for using accumArrayResult().
    5272                 :             :  * In the older scheme, you start with a NULL ArrayBuildState pointer, and
    5273                 :             :  * call accumArrayResult once per element.  In this scheme you end up with
    5274                 :             :  * a NULL pointer if there were no elements, which you need to special-case.
    5275                 :             :  * In the newer scheme, call initArrayResult and then call accumArrayResult
    5276                 :             :  * once per element.  In this scheme you always end with a non-NULL pointer
    5277                 :             :  * that you can pass to makeArrayResult; you get an empty array if there
    5278                 :             :  * were no elements.  This is preferred if an empty array is what you want.
    5279                 :             :  *
    5280                 :             :  * It's possible to choose whether to create a separate memory context for the
    5281                 :             :  * array build state, or whether to allocate it directly within rcontext.
    5282                 :             :  *
    5283                 :             :  * When there are many concurrent small states (e.g. array_agg() using hash
    5284                 :             :  * aggregation of many small groups), using a separate memory context for each
    5285                 :             :  * one may result in severe memory bloat. In such cases, use the same memory
    5286                 :             :  * context to initialize all such array build states, and pass
    5287                 :             :  * subcontext=false.
    5288                 :             :  *
    5289                 :             :  * In cases when the array build states have different lifetimes, using a
    5290                 :             :  * single memory context is impractical. Instead, pass subcontext=true so that
    5291                 :             :  * the array build states can be freed individually.
    5292                 :             :  */
    5293                 :             : ArrayBuildState *
    5294                 :        5988 : initArrayResult(Oid element_type, MemoryContext rcontext, bool subcontext)
    5295                 :             : {
    5296                 :             :         /*
    5297                 :             :          * When using a subcontext, we can afford to start with a somewhat larger
    5298                 :             :          * initial array size.  Without subcontexts, we'd better hope that most of
    5299                 :             :          * the states stay small ...
    5300                 :             :          */
    5301                 :       11976 :         return initArrayResultWithSize(element_type, rcontext, subcontext,
    5302                 :        5988 :                                                                    subcontext ? 64 : 8);
    5303                 :             : }
    5304                 :             : 
    5305                 :             : /*
    5306                 :             :  * initArrayResultWithSize
    5307                 :             :  *              As initArrayResult, but allow the initial size of the allocated arrays
    5308                 :             :  *              to be specified.
    5309                 :             :  */
    5310                 :             : ArrayBuildState *
    5311                 :        6018 : initArrayResultWithSize(Oid element_type, MemoryContext rcontext,
    5312                 :             :                                                 bool subcontext, int initsize)
    5313                 :             : {
    5314                 :        6018 :         ArrayBuildState *astate;
    5315                 :        6018 :         MemoryContext arr_context = rcontext;
    5316                 :             : 
    5317                 :             :         /* Make a temporary context to hold all the junk */
    5318         [ +  + ]:        6018 :         if (subcontext)
    5319                 :        1734 :                 arr_context = AllocSetContextCreate(rcontext,
    5320                 :             :                                                                                         "accumArrayResult",
    5321                 :             :                                                                                         ALLOCSET_DEFAULT_SIZES);
    5322                 :             : 
    5323                 :        6018 :         astate = (ArrayBuildState *)
    5324                 :        6018 :                 MemoryContextAlloc(arr_context, sizeof(ArrayBuildState));
    5325                 :        6018 :         astate->mcontext = arr_context;
    5326                 :        6018 :         astate->private_cxt = subcontext;
    5327                 :        6018 :         astate->alen = initsize;
    5328                 :        6018 :         astate->dvalues = (Datum *)
    5329                 :        6018 :                 MemoryContextAlloc(arr_context, astate->alen * sizeof(Datum));
    5330                 :        6018 :         astate->dnulls = (bool *)
    5331                 :        6018 :                 MemoryContextAlloc(arr_context, astate->alen * sizeof(bool));
    5332                 :        6018 :         astate->nelems = 0;
    5333                 :        6018 :         astate->element_type = element_type;
    5334                 :       12036 :         get_typlenbyvalalign(element_type,
    5335                 :        6018 :                                                  &astate->typlen,
    5336                 :        6018 :                                                  &astate->typbyval,
    5337                 :        6018 :                                                  &astate->typalign);
    5338                 :             : 
    5339                 :       12036 :         return astate;
    5340                 :        6018 : }
    5341                 :             : 
    5342                 :             : /*
    5343                 :             :  * accumArrayResult - accumulate one (more) Datum for an array result
    5344                 :             :  *
    5345                 :             :  *      astate is working state (can be NULL on first call)
    5346                 :             :  *      dvalue/disnull represent the new Datum to append to the array
    5347                 :             :  *      element_type is the Datum's type (must be a valid array element type)
    5348                 :             :  *      rcontext is where to keep working state
    5349                 :             :  */
    5350                 :             : ArrayBuildState *
    5351                 :      235655 : accumArrayResult(ArrayBuildState *astate,
    5352                 :             :                                  Datum dvalue, bool disnull,
    5353                 :             :                                  Oid element_type,
    5354                 :             :                                  MemoryContext rcontext)
    5355                 :             : {
    5356                 :      235655 :         MemoryContext oldcontext;
    5357                 :             : 
    5358         [ +  + ]:      235655 :         if (astate == NULL)
    5359                 :             :         {
    5360                 :             :                 /* First time through --- initialize */
    5361                 :         521 :                 astate = initArrayResult(element_type, rcontext, true);
    5362                 :         521 :         }
    5363                 :             :         else
    5364                 :             :         {
    5365         [ +  - ]:      235134 :                 Assert(astate->element_type == element_type);
    5366                 :             :         }
    5367                 :             : 
    5368                 :      235655 :         oldcontext = MemoryContextSwitchTo(astate->mcontext);
    5369                 :             : 
    5370                 :             :         /* enlarge dvalues[]/dnulls[] if needed */
    5371         [ +  + ]:      235655 :         if (astate->nelems >= astate->alen)
    5372                 :             :         {
    5373                 :        2943 :                 astate->alen *= 2;
    5374                 :             :                 /* give an array-related error if we go past MaxAllocSize */
    5375         [ +  - ]:        2943 :                 if (!AllocSizeIsValid(astate->alen * sizeof(Datum)))
    5376   [ #  #  #  # ]:           0 :                         ereport(ERROR,
    5377                 :             :                                         (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    5378                 :             :                                          errmsg("array size exceeds the maximum allowed (%zu)",
    5379                 :             :                                                         MaxAllocSize)));
    5380                 :        2943 :                 astate->dvalues = (Datum *)
    5381                 :        2943 :                         repalloc(astate->dvalues, astate->alen * sizeof(Datum));
    5382                 :        2943 :                 astate->dnulls = (bool *)
    5383                 :        2943 :                         repalloc(astate->dnulls, astate->alen * sizeof(bool));
    5384                 :        2943 :         }
    5385                 :             : 
    5386                 :             :         /*
    5387                 :             :          * Ensure pass-by-ref stuff is copied into mcontext; and detoast it too if
    5388                 :             :          * it's varlena.  (You might think that detoasting is not needed here
    5389                 :             :          * because construct_md_array can detoast the array elements later.
    5390                 :             :          * However, we must not let construct_md_array modify the ArrayBuildState
    5391                 :             :          * because that would mean array_agg_finalfn damages its input, which is
    5392                 :             :          * verboten.  Also, this way frequently saves one copying step.)
    5393                 :             :          */
    5394   [ +  +  +  + ]:      235655 :         if (!disnull && !astate->typbyval)
    5395                 :             :         {
    5396         [ +  + ]:      172071 :                 if (astate->typlen == -1)
    5397                 :       70830 :                         dvalue = PointerGetDatum(PG_DETOAST_DATUM_COPY(dvalue));
    5398                 :             :                 else
    5399                 :      101241 :                         dvalue = datumCopy(dvalue, astate->typbyval, astate->typlen);
    5400                 :      172071 :         }
    5401                 :             : 
    5402                 :      235655 :         astate->dvalues[astate->nelems] = dvalue;
    5403                 :      235655 :         astate->dnulls[astate->nelems] = disnull;
    5404                 :      235655 :         astate->nelems++;
    5405                 :             : 
    5406                 :      235655 :         MemoryContextSwitchTo(oldcontext);
    5407                 :             : 
    5408                 :      471310 :         return astate;
    5409                 :      235655 : }
    5410                 :             : 
    5411                 :             : /*
    5412                 :             :  * makeArrayResult - produce 1-D final result of accumArrayResult
    5413                 :             :  *
    5414                 :             :  * Note: only releases astate if it was initialized within a separate memory
    5415                 :             :  * context (i.e. using subcontext=true when calling initArrayResult).
    5416                 :             :  *
    5417                 :             :  *      astate is working state (must not be NULL)
    5418                 :             :  *      rcontext is where to construct result
    5419                 :             :  */
    5420                 :             : Datum
    5421                 :         539 : makeArrayResult(ArrayBuildState *astate,
    5422                 :             :                                 MemoryContext rcontext)
    5423                 :             : {
    5424                 :         539 :         int                     ndims;
    5425                 :         539 :         int                     dims[1];
    5426                 :         539 :         int                     lbs[1];
    5427                 :             : 
    5428                 :             :         /* If no elements were presented, we want to create an empty array */
    5429                 :         539 :         ndims = (astate->nelems > 0) ? 1 : 0;
    5430                 :         539 :         dims[0] = astate->nelems;
    5431                 :         539 :         lbs[0] = 1;
    5432                 :             : 
    5433                 :        1617 :         return makeMdArrayResult(astate, ndims, dims, lbs, rcontext,
    5434                 :         539 :                                                          astate->private_cxt);
    5435                 :         539 : }
    5436                 :             : 
    5437                 :             : /*
    5438                 :             :  * makeMdArrayResult - produce multi-D final result of accumArrayResult
    5439                 :             :  *
    5440                 :             :  * beware: no check that specified dimensions match the number of values
    5441                 :             :  * accumulated.
    5442                 :             :  *
    5443                 :             :  * Note: if the astate was not initialized within a separate memory context
    5444                 :             :  * (that is, initArrayResult was called with subcontext=false), then using
    5445                 :             :  * release=true is illegal. Instead, release astate along with the rest of its
    5446                 :             :  * context when appropriate.
    5447                 :             :  *
    5448                 :             :  *      astate is working state (must not be NULL)
    5449                 :             :  *      rcontext is where to construct result
    5450                 :             :  *      release is true if okay to release working state
    5451                 :             :  */
    5452                 :             : Datum
    5453                 :        5805 : makeMdArrayResult(ArrayBuildState *astate,
    5454                 :             :                                   int ndims,
    5455                 :             :                                   int *dims,
    5456                 :             :                                   int *lbs,
    5457                 :             :                                   MemoryContext rcontext,
    5458                 :             :                                   bool release)
    5459                 :             : {
    5460                 :        5805 :         ArrayType  *result;
    5461                 :        5805 :         MemoryContext oldcontext;
    5462                 :             : 
    5463                 :             :         /* Build the final array result in rcontext */
    5464                 :        5805 :         oldcontext = MemoryContextSwitchTo(rcontext);
    5465                 :             : 
    5466                 :       11610 :         result = construct_md_array(astate->dvalues,
    5467                 :        5805 :                                                                 astate->dnulls,
    5468                 :        5805 :                                                                 ndims,
    5469                 :        5805 :                                                                 dims,
    5470                 :        5805 :                                                                 lbs,
    5471                 :        5805 :                                                                 astate->element_type,
    5472                 :        5805 :                                                                 astate->typlen,
    5473                 :        5805 :                                                                 astate->typbyval,
    5474                 :        5805 :                                                                 astate->typalign);
    5475                 :             : 
    5476                 :        5805 :         MemoryContextSwitchTo(oldcontext);
    5477                 :             : 
    5478                 :             :         /* Clean up all the junk */
    5479         [ +  + ]:        5805 :         if (release)
    5480                 :             :         {
    5481         [ +  - ]:        1636 :                 Assert(astate->private_cxt);
    5482                 :        1636 :                 MemoryContextDelete(astate->mcontext);
    5483                 :        1636 :         }
    5484                 :             : 
    5485                 :       11610 :         return PointerGetDatum(result);
    5486                 :        5805 : }
    5487                 :             : 
    5488                 :             : /*
    5489                 :             :  * The following three functions provide essentially the same API as
    5490                 :             :  * initArrayResult/accumArrayResult/makeArrayResult, but instead of accepting
    5491                 :             :  * inputs that are array elements, they accept inputs that are arrays and
    5492                 :             :  * produce an output array having N+1 dimensions.  The inputs must all have
    5493                 :             :  * identical dimensionality as well as element type.
    5494                 :             :  */
    5495                 :             : 
    5496                 :             : /*
    5497                 :             :  * initArrayResultArr - initialize an empty ArrayBuildStateArr
    5498                 :             :  *
    5499                 :             :  *      array_type is the array type (must be a valid varlena array type)
    5500                 :             :  *      element_type is the type of the array's elements (lookup if InvalidOid)
    5501                 :             :  *      rcontext is where to keep working state
    5502                 :             :  *      subcontext is a flag determining whether to use a separate memory context
    5503                 :             :  */
    5504                 :             : ArrayBuildStateArr *
    5505                 :          82 : initArrayResultArr(Oid array_type, Oid element_type, MemoryContext rcontext,
    5506                 :             :                                    bool subcontext)
    5507                 :             : {
    5508                 :          82 :         ArrayBuildStateArr *astate;
    5509                 :          82 :         MemoryContext arr_context = rcontext;   /* by default use the parent ctx */
    5510                 :             : 
    5511                 :             :         /* Lookup element type, unless element_type already provided */
    5512         [ +  + ]:          82 :         if (!OidIsValid(element_type))
    5513                 :             :         {
    5514                 :          62 :                 element_type = get_element_type(array_type);
    5515                 :             : 
    5516         [ +  - ]:          62 :                 if (!OidIsValid(element_type))
    5517   [ #  #  #  # ]:           0 :                         ereport(ERROR,
    5518                 :             :                                         (errcode(ERRCODE_DATATYPE_MISMATCH),
    5519                 :             :                                          errmsg("data type %s is not an array type",
    5520                 :             :                                                         format_type_be(array_type))));
    5521                 :          62 :         }
    5522                 :             : 
    5523                 :             :         /* Make a temporary context to hold all the junk */
    5524         [ +  + ]:          82 :         if (subcontext)
    5525                 :           8 :                 arr_context = AllocSetContextCreate(rcontext,
    5526                 :             :                                                                                         "accumArrayResultArr",
    5527                 :             :                                                                                         ALLOCSET_DEFAULT_SIZES);
    5528                 :             : 
    5529                 :             :         /* Note we initialize all fields to zero */
    5530                 :          82 :         astate = (ArrayBuildStateArr *)
    5531                 :          82 :                 MemoryContextAllocZero(arr_context, sizeof(ArrayBuildStateArr));
    5532                 :          82 :         astate->mcontext = arr_context;
    5533                 :          82 :         astate->private_cxt = subcontext;
    5534                 :             : 
    5535                 :             :         /* Save relevant datatype information */
    5536                 :          82 :         astate->array_type = array_type;
    5537                 :          82 :         astate->element_type = element_type;
    5538                 :             : 
    5539                 :         164 :         return astate;
    5540                 :          82 : }
    5541                 :             : 
    5542                 :             : /*
    5543                 :             :  * accumArrayResultArr - accumulate one (more) sub-array for an array result
    5544                 :             :  *
    5545                 :             :  *      astate is working state (can be NULL on first call)
    5546                 :             :  *      dvalue/disnull represent the new sub-array to append to the array
    5547                 :             :  *      array_type is the array type (must be a valid varlena array type)
    5548                 :             :  *      rcontext is where to keep working state
    5549                 :             :  */
    5550                 :             : ArrayBuildStateArr *
    5551                 :       10060 : accumArrayResultArr(ArrayBuildStateArr *astate,
    5552                 :             :                                         Datum dvalue, bool disnull,
    5553                 :             :                                         Oid array_type,
    5554                 :             :                                         MemoryContext rcontext)
    5555                 :             : {
    5556                 :       10060 :         ArrayType  *arg;
    5557                 :       10060 :         MemoryContext oldcontext;
    5558                 :       10060 :         int                *dims,
    5559                 :             :                            *lbs,
    5560                 :             :                                 ndims,
    5561                 :             :                                 nitems,
    5562                 :             :                                 ndatabytes;
    5563                 :       10060 :         char       *data;
    5564                 :       10060 :         int                     i;
    5565                 :             : 
    5566                 :             :         /*
    5567                 :             :          * We disallow accumulating null subarrays.  Another plausible definition
    5568                 :             :          * is to ignore them, but callers that want that can just skip calling
    5569                 :             :          * this function.
    5570                 :             :          */
    5571         [ +  + ]:       10060 :         if (disnull)
    5572   [ +  -  +  - ]:           1 :                 ereport(ERROR,
    5573                 :             :                                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    5574                 :             :                                  errmsg("cannot accumulate null arrays")));
    5575                 :             : 
    5576                 :             :         /* Detoast input array in caller's context */
    5577                 :       10059 :         arg = DatumGetArrayTypeP(dvalue);
    5578                 :             : 
    5579         [ +  - ]:       10059 :         if (astate == NULL)
    5580                 :           0 :                 astate = initArrayResultArr(array_type, InvalidOid, rcontext, true);
    5581                 :             :         else
    5582         [ +  - ]:       10059 :                 Assert(astate->array_type == array_type);
    5583                 :             : 
    5584                 :       10059 :         oldcontext = MemoryContextSwitchTo(astate->mcontext);
    5585                 :             : 
    5586                 :             :         /* Collect this input's dimensions */
    5587                 :       10059 :         ndims = ARR_NDIM(arg);
    5588                 :       10059 :         dims = ARR_DIMS(arg);
    5589                 :       10059 :         lbs = ARR_LBOUND(arg);
    5590         [ +  + ]:       10059 :         data = ARR_DATA_PTR(arg);
    5591                 :       10059 :         nitems = ArrayGetNItems(ndims, dims);
    5592         [ +  + ]:       10059 :         ndatabytes = ARR_SIZE(arg) - ARR_DATA_OFFSET(arg);
    5593                 :             : 
    5594         [ +  + ]:       10059 :         if (astate->ndims == 0)
    5595                 :             :         {
    5596                 :             :                 /* First input; check/save the dimensionality info */
    5597                 :             : 
    5598                 :             :                 /* Should we allow empty inputs and just produce an empty output? */
    5599         [ +  + ]:          51 :                 if (ndims == 0)
    5600   [ +  -  +  - ]:           1 :                         ereport(ERROR,
    5601                 :             :                                         (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    5602                 :             :                                          errmsg("cannot accumulate empty arrays")));
    5603         [ +  - ]:          50 :                 if (ndims + 1 > MAXDIM)
    5604   [ #  #  #  # ]:           0 :                         ereport(ERROR,
    5605                 :             :                                         (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    5606                 :             :                                          errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
    5607                 :             :                                                         ndims + 1, MAXDIM)));
    5608                 :             : 
    5609                 :             :                 /*
    5610                 :             :                  * The output array will have n+1 dimensions, with the ones after the
    5611                 :             :                  * first matching the input's dimensions.
    5612                 :             :                  */
    5613                 :          50 :                 astate->ndims = ndims + 1;
    5614                 :          50 :                 astate->dims[0] = 0;
    5615                 :          50 :                 memcpy(&astate->dims[1], dims, ndims * sizeof(int));
    5616                 :          50 :                 astate->lbs[0] = 1;
    5617                 :          50 :                 memcpy(&astate->lbs[1], lbs, ndims * sizeof(int));
    5618                 :             : 
    5619                 :             :                 /* Allocate at least enough data space for this item */
    5620         [ +  - ]:          50 :                 astate->abytes = pg_nextpower2_32(Max(1024, ndatabytes + 1));
    5621                 :          50 :                 astate->data = (char *) palloc(astate->abytes);
    5622                 :          50 :         }
    5623                 :             :         else
    5624                 :             :         {
    5625                 :             :                 /* Second or later input: must match first input's dimensionality */
    5626         [ +  - ]:       10008 :                 if (astate->ndims != ndims + 1)
    5627   [ #  #  #  # ]:           0 :                         ereport(ERROR,
    5628                 :             :                                         (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    5629                 :             :                                          errmsg("cannot accumulate arrays of different dimensionality")));
    5630         [ +  + ]:       20015 :                 for (i = 0; i < ndims; i++)
    5631                 :             :                 {
    5632         [ +  + ]:       10008 :                         if (astate->dims[i + 1] != dims[i] || astate->lbs[i + 1] != lbs[i])
    5633   [ +  -  +  - ]:           1 :                                 ereport(ERROR,
    5634                 :             :                                                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    5635                 :             :                                                  errmsg("cannot accumulate arrays of different dimensionality")));
    5636                 :       10007 :                 }
    5637                 :             : 
    5638                 :             :                 /* Enlarge data space if needed */
    5639         [ +  + ]:       10007 :                 if (astate->nbytes + ndatabytes > astate->abytes)
    5640                 :             :                 {
    5641         [ +  - ]:          10 :                         astate->abytes = Max(astate->abytes * 2,
    5642                 :             :                                                                  astate->nbytes + ndatabytes);
    5643                 :          10 :                         astate->data = (char *) repalloc(astate->data, astate->abytes);
    5644                 :          10 :                 }
    5645                 :             :         }
    5646                 :             : 
    5647                 :             :         /*
    5648                 :             :          * Copy the data portion of the sub-array.  Note we assume that the
    5649                 :             :          * advertised data length of the sub-array is properly aligned.  We do not
    5650                 :             :          * have to worry about detoasting elements since whatever's in the
    5651                 :             :          * sub-array should be OK already.
    5652                 :             :          */
    5653                 :       10057 :         memcpy(astate->data + astate->nbytes, data, ndatabytes);
    5654                 :       10057 :         astate->nbytes += ndatabytes;
    5655                 :             : 
    5656                 :             :         /* Deal with null bitmap if needed */
    5657   [ +  +  +  + ]:       10057 :         if (astate->nullbitmap || ARR_HASNULL(arg))
    5658                 :             :         {
    5659                 :        4995 :                 int                     newnitems = astate->nitems + nitems;
    5660                 :             : 
    5661         [ +  + ]:        4995 :                 if (astate->nullbitmap == NULL)
    5662                 :             :                 {
    5663                 :             :                         /*
    5664                 :             :                          * First input with nulls; we must retrospectively handle any
    5665                 :             :                          * previous inputs by marking all their items non-null.
    5666                 :             :                          */
    5667         [ +  - ]:          16 :                         astate->aitems = pg_nextpower2_32(Max(256, newnitems + 1));
    5668                 :          16 :                         astate->nullbitmap = (bits8 *) palloc((astate->aitems + 7) / 8);
    5669                 :          32 :                         array_bitmap_copy(astate->nullbitmap, 0,
    5670                 :             :                                                           NULL, 0,
    5671                 :          16 :                                                           astate->nitems);
    5672                 :          16 :                 }
    5673         [ +  + ]:        4979 :                 else if (newnitems > astate->aitems)
    5674                 :             :                 {
    5675         [ +  - ]:          10 :                         astate->aitems = Max(astate->aitems * 2, newnitems);
    5676                 :          10 :                         astate->nullbitmap = (bits8 *)
    5677                 :          10 :                                 repalloc(astate->nullbitmap, (astate->aitems + 7) / 8);
    5678                 :          10 :                 }
    5679                 :        9990 :                 array_bitmap_copy(astate->nullbitmap, astate->nitems,
    5680         [ +  + ]:        4995 :                                                   ARR_NULLBITMAP(arg), 0,
    5681                 :        4995 :                                                   nitems);
    5682                 :        4995 :         }
    5683                 :             : 
    5684                 :       10057 :         astate->nitems += nitems;
    5685                 :       10057 :         astate->dims[0] += 1;
    5686                 :             : 
    5687                 :       10057 :         MemoryContextSwitchTo(oldcontext);
    5688                 :             : 
    5689                 :             :         /* Release detoasted copy if any */
    5690         [ +  + ]:       10057 :         if (arg != DatumGetPointer(dvalue))
    5691                 :          21 :                 pfree(arg);
    5692                 :             : 
    5693                 :       20114 :         return astate;
    5694                 :       10057 : }
    5695                 :             : 
    5696                 :             : /*
    5697                 :             :  * makeArrayResultArr - produce N+1-D final result of accumArrayResultArr
    5698                 :             :  *
    5699                 :             :  *      astate is working state (must not be NULL)
    5700                 :             :  *      rcontext is where to construct result
    5701                 :             :  *      release is true if okay to release working state
    5702                 :             :  */
    5703                 :             : Datum
    5704                 :          39 : makeArrayResultArr(ArrayBuildStateArr *astate,
    5705                 :             :                                    MemoryContext rcontext,
    5706                 :             :                                    bool release)
    5707                 :             : {
    5708                 :          39 :         ArrayType  *result;
    5709                 :          39 :         MemoryContext oldcontext;
    5710                 :             : 
    5711                 :             :         /* Build the final array result in rcontext */
    5712                 :          39 :         oldcontext = MemoryContextSwitchTo(rcontext);
    5713                 :             : 
    5714         [ +  - ]:          39 :         if (astate->ndims == 0)
    5715                 :             :         {
    5716                 :             :                 /* No inputs, return empty array */
    5717                 :           0 :                 result = construct_empty_array(astate->element_type);
    5718                 :           0 :         }
    5719                 :             :         else
    5720                 :             :         {
    5721                 :          39 :                 int                     dataoffset,
    5722                 :             :                                         nbytes;
    5723                 :             : 
    5724                 :             :                 /* Check for overflow of the array dimensions */
    5725                 :          39 :                 (void) ArrayGetNItems(astate->ndims, astate->dims);
    5726                 :          39 :                 ArrayCheckBounds(astate->ndims, astate->dims, astate->lbs);
    5727                 :             : 
    5728                 :             :                 /* Compute required space */
    5729                 :          39 :                 nbytes = astate->nbytes;
    5730         [ +  + ]:          39 :                 if (astate->nullbitmap != NULL)
    5731                 :             :                 {
    5732                 :          11 :                         dataoffset = ARR_OVERHEAD_WITHNULLS(astate->ndims, astate->nitems);
    5733                 :          11 :                         nbytes += dataoffset;
    5734                 :          11 :                 }
    5735                 :             :                 else
    5736                 :             :                 {
    5737                 :          28 :                         dataoffset = 0;
    5738                 :          28 :                         nbytes += ARR_OVERHEAD_NONULLS(astate->ndims);
    5739                 :             :                 }
    5740                 :             : 
    5741                 :          39 :                 result = (ArrayType *) palloc0(nbytes);
    5742                 :          39 :                 SET_VARSIZE(result, nbytes);
    5743                 :          39 :                 result->ndim = astate->ndims;
    5744                 :          39 :                 result->dataoffset = dataoffset;
    5745                 :          39 :                 result->elemtype = astate->element_type;
    5746                 :             : 
    5747                 :          39 :                 memcpy(ARR_DIMS(result), astate->dims, astate->ndims * sizeof(int));
    5748                 :          39 :                 memcpy(ARR_LBOUND(result), astate->lbs, astate->ndims * sizeof(int));
    5749   [ +  +  +  + ]:          39 :                 memcpy(ARR_DATA_PTR(result), astate->data, astate->nbytes);
    5750                 :             : 
    5751         [ +  + ]:          39 :                 if (astate->nullbitmap != NULL)
    5752         [ +  - ]:          11 :                         array_bitmap_copy(ARR_NULLBITMAP(result), 0,
    5753                 :          11 :                                                           astate->nullbitmap, 0,
    5754                 :          11 :                                                           astate->nitems);
    5755                 :          39 :         }
    5756                 :             : 
    5757                 :          39 :         MemoryContextSwitchTo(oldcontext);
    5758                 :             : 
    5759                 :             :         /* Clean up all the junk */
    5760         [ +  + ]:          39 :         if (release)
    5761                 :             :         {
    5762         [ +  - ]:           8 :                 Assert(astate->private_cxt);
    5763                 :           8 :                 MemoryContextDelete(astate->mcontext);
    5764                 :           8 :         }
    5765                 :             : 
    5766                 :          78 :         return PointerGetDatum(result);
    5767                 :          39 : }
    5768                 :             : 
    5769                 :             : /*
    5770                 :             :  * The following three functions provide essentially the same API as
    5771                 :             :  * initArrayResult/accumArrayResult/makeArrayResult, but can accept either
    5772                 :             :  * scalar or array inputs, invoking the appropriate set of functions above.
    5773                 :             :  */
    5774                 :             : 
    5775                 :             : /*
    5776                 :             :  * initArrayResultAny - initialize an empty ArrayBuildStateAny
    5777                 :             :  *
    5778                 :             :  *      input_type is the input datatype (either element or array type)
    5779                 :             :  *      rcontext is where to keep working state
    5780                 :             :  *      subcontext is a flag determining whether to use a separate memory context
    5781                 :             :  */
    5782                 :             : ArrayBuildStateAny *
    5783                 :         840 : initArrayResultAny(Oid input_type, MemoryContext rcontext, bool subcontext)
    5784                 :             : {
    5785                 :         840 :         ArrayBuildStateAny *astate;
    5786                 :             : 
    5787                 :             :         /*
    5788                 :             :          * int2vector and oidvector will satisfy both get_element_type and
    5789                 :             :          * get_array_type.  We prefer to treat them as scalars, to be consistent
    5790                 :             :          * with get_promoted_array_type.  Hence, check get_array_type not
    5791                 :             :          * get_element_type.
    5792                 :             :          */
    5793         [ +  + ]:         840 :         if (!OidIsValid(get_array_type(input_type)))
    5794                 :             :         {
    5795                 :             :                 /* Array case */
    5796                 :           8 :                 ArrayBuildStateArr *arraystate;
    5797                 :             : 
    5798                 :           8 :                 arraystate = initArrayResultArr(input_type, InvalidOid, rcontext, subcontext);
    5799                 :           8 :                 astate = (ArrayBuildStateAny *)
    5800                 :           8 :                         MemoryContextAlloc(arraystate->mcontext,
    5801                 :             :                                                            sizeof(ArrayBuildStateAny));
    5802                 :           8 :                 astate->scalarstate = NULL;
    5803                 :           8 :                 astate->arraystate = arraystate;
    5804                 :           8 :         }
    5805                 :             :         else
    5806                 :             :         {
    5807                 :             :                 /* Scalar case */
    5808                 :         832 :                 ArrayBuildState *scalarstate;
    5809                 :             : 
    5810                 :         832 :                 scalarstate = initArrayResult(input_type, rcontext, subcontext);
    5811                 :         832 :                 astate = (ArrayBuildStateAny *)
    5812                 :         832 :                         MemoryContextAlloc(scalarstate->mcontext,
    5813                 :             :                                                            sizeof(ArrayBuildStateAny));
    5814                 :         832 :                 astate->scalarstate = scalarstate;
    5815                 :         832 :                 astate->arraystate = NULL;
    5816                 :         832 :         }
    5817                 :             : 
    5818                 :        1680 :         return astate;
    5819                 :         840 : }
    5820                 :             : 
    5821                 :             : /*
    5822                 :             :  * accumArrayResultAny - accumulate one (more) input for an array result
    5823                 :             :  *
    5824                 :             :  *      astate is working state (can be NULL on first call)
    5825                 :             :  *      dvalue/disnull represent the new input to append to the array
    5826                 :             :  *      input_type is the input datatype (either element or array type)
    5827                 :             :  *      rcontext is where to keep working state
    5828                 :             :  */
    5829                 :             : ArrayBuildStateAny *
    5830                 :        2109 : accumArrayResultAny(ArrayBuildStateAny *astate,
    5831                 :             :                                         Datum dvalue, bool disnull,
    5832                 :             :                                         Oid input_type,
    5833                 :             :                                         MemoryContext rcontext)
    5834                 :             : {
    5835         [ +  + ]:        2109 :         if (astate == NULL)
    5836                 :          20 :                 astate = initArrayResultAny(input_type, rcontext, true);
    5837                 :             : 
    5838         [ +  + ]:        2109 :         if (astate->scalarstate)
    5839                 :        4172 :                 (void) accumArrayResult(astate->scalarstate,
    5840                 :        2086 :                                                                 dvalue, disnull,
    5841                 :        2086 :                                                                 input_type, rcontext);
    5842                 :             :         else
    5843                 :          46 :                 (void) accumArrayResultArr(astate->arraystate,
    5844                 :          23 :                                                                    dvalue, disnull,
    5845                 :          23 :                                                                    input_type, rcontext);
    5846                 :             : 
    5847                 :        2109 :         return astate;
    5848                 :             : }
    5849                 :             : 
    5850                 :             : /*
    5851                 :             :  * makeArrayResultAny - produce final result of accumArrayResultAny
    5852                 :             :  *
    5853                 :             :  *      astate is working state (must not be NULL)
    5854                 :             :  *      rcontext is where to construct result
    5855                 :             :  *      release is true if okay to release working state
    5856                 :             :  */
    5857                 :             : Datum
    5858                 :         840 : makeArrayResultAny(ArrayBuildStateAny *astate,
    5859                 :             :                                    MemoryContext rcontext, bool release)
    5860                 :             : {
    5861                 :         840 :         Datum           result;
    5862                 :             : 
    5863         [ +  + ]:         840 :         if (astate->scalarstate)
    5864                 :             :         {
    5865                 :             :                 /* Must use makeMdArrayResult to support "release" parameter */
    5866                 :         832 :                 int                     ndims;
    5867                 :         832 :                 int                     dims[1];
    5868                 :         832 :                 int                     lbs[1];
    5869                 :             : 
    5870                 :             :                 /* If no elements were presented, we want to create an empty array */
    5871                 :         832 :                 ndims = (astate->scalarstate->nelems > 0) ? 1 : 0;
    5872                 :         832 :                 dims[0] = astate->scalarstate->nelems;
    5873                 :         832 :                 lbs[0] = 1;
    5874                 :             : 
    5875                 :        1664 :                 result = makeMdArrayResult(astate->scalarstate, ndims, dims, lbs,
    5876                 :         832 :                                                                    rcontext, release);
    5877                 :         832 :         }
    5878                 :             :         else
    5879                 :             :         {
    5880                 :          16 :                 result = makeArrayResultArr(astate->arraystate,
    5881                 :           8 :                                                                         rcontext, release);
    5882                 :             :         }
    5883                 :        1680 :         return result;
    5884                 :         840 : }
    5885                 :             : 
    5886                 :             : 
    5887                 :             : Datum
    5888                 :          47 : array_larger(PG_FUNCTION_ARGS)
    5889                 :             : {
    5890         [ +  + ]:          47 :         if (array_cmp(fcinfo) > 0)
    5891                 :          24 :                 PG_RETURN_DATUM(PG_GETARG_DATUM(0));
    5892                 :             :         else
    5893                 :          23 :                 PG_RETURN_DATUM(PG_GETARG_DATUM(1));
    5894                 :          47 : }
    5895                 :             : 
    5896                 :             : Datum
    5897                 :          43 : array_smaller(PG_FUNCTION_ARGS)
    5898                 :             : {
    5899         [ +  + ]:          43 :         if (array_cmp(fcinfo) < 0)
    5900                 :          29 :                 PG_RETURN_DATUM(PG_GETARG_DATUM(0));
    5901                 :             :         else
    5902                 :          14 :                 PG_RETURN_DATUM(PG_GETARG_DATUM(1));
    5903                 :          43 : }
    5904                 :             : 
    5905                 :             : 
    5906                 :             : typedef struct generate_subscripts_fctx
    5907                 :             : {
    5908                 :             :         int32           lower;
    5909                 :             :         int32           upper;
    5910                 :             :         bool            reverse;
    5911                 :             : } generate_subscripts_fctx;
    5912                 :             : 
    5913                 :             : /*
    5914                 :             :  * generate_subscripts(array anyarray, dim int [, reverse bool])
    5915                 :             :  *              Returns all subscripts of the array for any dimension
    5916                 :             :  */
    5917                 :             : Datum
    5918                 :         151 : generate_subscripts(PG_FUNCTION_ARGS)
    5919                 :             : {
    5920                 :         151 :         FuncCallContext *funcctx;
    5921                 :         151 :         MemoryContext oldcontext;
    5922                 :         151 :         generate_subscripts_fctx *fctx;
    5923                 :             : 
    5924                 :             :         /* stuff done only on the first call of the function */
    5925         [ +  + ]:         151 :         if (SRF_IS_FIRSTCALL())
    5926                 :             :         {
    5927                 :          48 :                 AnyArrayType *v = PG_GETARG_ANY_ARRAY_P(0);
    5928                 :          48 :                 int                     reqdim = PG_GETARG_INT32(1);
    5929                 :          48 :                 int                *lb,
    5930                 :             :                                    *dimv;
    5931                 :             : 
    5932                 :             :                 /* create a function context for cross-call persistence */
    5933                 :          48 :                 funcctx = SRF_FIRSTCALL_INIT();
    5934                 :             : 
    5935                 :             :                 /* Sanity check: does it look like an array at all? */
    5936   [ +  -  +  +  :          48 :                 if (AARR_NDIM(v) <= 0 || AARR_NDIM(v) > MAXDIM)
             +  -  -  + ]
    5937         [ +  - ]:           1 :                         SRF_RETURN_DONE(funcctx);
    5938                 :             : 
    5939                 :             :                 /* Sanity check: was the requested dim valid */
    5940   [ -  +  +  -  :          47 :                 if (reqdim <= 0 || reqdim > AARR_NDIM(v))
                   -  + ]
    5941         [ #  # ]:           0 :                         SRF_RETURN_DONE(funcctx);
    5942                 :             : 
    5943                 :             :                 /*
    5944                 :             :                  * switch to memory context appropriate for multiple function calls
    5945                 :             :                  */
    5946                 :          47 :                 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
    5947                 :          47 :                 fctx = palloc_object(generate_subscripts_fctx);
    5948                 :             : 
    5949         [ +  - ]:          47 :                 lb = AARR_LBOUND(v);
    5950         [ +  - ]:          47 :                 dimv = AARR_DIMS(v);
    5951                 :             : 
    5952                 :          47 :                 fctx->lower = lb[reqdim - 1];
    5953                 :          47 :                 fctx->upper = dimv[reqdim - 1] + lb[reqdim - 1] - 1;
    5954         [ +  - ]:          47 :                 fctx->reverse = (PG_NARGS() < 3) ? false : PG_GETARG_BOOL(2);
    5955                 :             : 
    5956                 :          47 :                 funcctx->user_fctx = fctx;
    5957                 :             : 
    5958                 :          47 :                 MemoryContextSwitchTo(oldcontext);
    5959         [ +  + ]:          48 :         }
    5960                 :             : 
    5961                 :         150 :         funcctx = SRF_PERCALL_SETUP();
    5962                 :             : 
    5963                 :         150 :         fctx = funcctx->user_fctx;
    5964                 :             : 
    5965         [ +  + ]:         150 :         if (fctx->lower <= fctx->upper)
    5966                 :             :         {
    5967         [ -  + ]:         103 :                 if (!fctx->reverse)
    5968                 :         103 :                         SRF_RETURN_NEXT(funcctx, Int32GetDatum(fctx->lower++));
    5969                 :             :                 else
    5970                 :           0 :                         SRF_RETURN_NEXT(funcctx, Int32GetDatum(fctx->upper--));
    5971                 :           0 :         }
    5972                 :             :         else
    5973                 :             :                 /* done when there are no more elements left */
    5974         [ +  - ]:          47 :                 SRF_RETURN_DONE(funcctx);
    5975         [ -  + ]:         151 : }
    5976                 :             : 
    5977                 :             : /*
    5978                 :             :  * generate_subscripts_nodir
    5979                 :             :  *              Implements the 2-argument version of generate_subscripts
    5980                 :             :  */
    5981                 :             : Datum
    5982                 :         151 : generate_subscripts_nodir(PG_FUNCTION_ARGS)
    5983                 :             : {
    5984                 :             :         /* just call the other one -- it can handle both cases */
    5985                 :         151 :         return generate_subscripts(fcinfo);
    5986                 :             : }
    5987                 :             : 
    5988                 :             : /*
    5989                 :             :  * array_fill_with_lower_bounds
    5990                 :             :  *              Create and fill array with defined lower bounds.
    5991                 :             :  */
    5992                 :             : Datum
    5993                 :          11 : array_fill_with_lower_bounds(PG_FUNCTION_ARGS)
    5994                 :             : {
    5995                 :          11 :         ArrayType  *dims;
    5996                 :          11 :         ArrayType  *lbs;
    5997                 :          11 :         ArrayType  *result;
    5998                 :          11 :         Oid                     elmtype;
    5999                 :          11 :         Datum           value;
    6000                 :          11 :         bool            isnull;
    6001                 :             : 
    6002         [ +  + ]:          11 :         if (PG_ARGISNULL(1) || PG_ARGISNULL(2))
    6003   [ +  -  +  - ]:           2 :                 ereport(ERROR,
    6004                 :             :                                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    6005                 :             :                                  errmsg("dimension array or low bound array cannot be null")));
    6006                 :             : 
    6007                 :           9 :         dims = PG_GETARG_ARRAYTYPE_P(1);
    6008                 :           9 :         lbs = PG_GETARG_ARRAYTYPE_P(2);
    6009                 :             : 
    6010         [ +  + ]:           9 :         if (!PG_ARGISNULL(0))
    6011                 :             :         {
    6012                 :           7 :                 value = PG_GETARG_DATUM(0);
    6013                 :           7 :                 isnull = false;
    6014                 :           7 :         }
    6015                 :             :         else
    6016                 :             :         {
    6017                 :           2 :                 value = 0;
    6018                 :           2 :                 isnull = true;
    6019                 :             :         }
    6020                 :             : 
    6021                 :           9 :         elmtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
    6022         [ +  - ]:           9 :         if (!OidIsValid(elmtype))
    6023   [ #  #  #  # ]:           0 :                 elog(ERROR, "could not determine data type of input");
    6024                 :             : 
    6025                 :           9 :         result = array_fill_internal(dims, lbs, value, isnull, elmtype, fcinfo);
    6026                 :          18 :         PG_RETURN_ARRAYTYPE_P(result);
    6027                 :           9 : }
    6028                 :             : 
    6029                 :             : /*
    6030                 :             :  * array_fill
    6031                 :             :  *              Create and fill array with default lower bounds.
    6032                 :             :  */
    6033                 :             : Datum
    6034                 :          15 : array_fill(PG_FUNCTION_ARGS)
    6035                 :             : {
    6036                 :          15 :         ArrayType  *dims;
    6037                 :          15 :         ArrayType  *result;
    6038                 :          15 :         Oid                     elmtype;
    6039                 :          15 :         Datum           value;
    6040                 :          15 :         bool            isnull;
    6041                 :             : 
    6042         [ +  - ]:          15 :         if (PG_ARGISNULL(1))
    6043   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    6044                 :             :                                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    6045                 :             :                                  errmsg("dimension array or low bound array cannot be null")));
    6046                 :             : 
    6047                 :          15 :         dims = PG_GETARG_ARRAYTYPE_P(1);
    6048                 :             : 
    6049         [ +  + ]:          15 :         if (!PG_ARGISNULL(0))
    6050                 :             :         {
    6051                 :          13 :                 value = PG_GETARG_DATUM(0);
    6052                 :          13 :                 isnull = false;
    6053                 :          13 :         }
    6054                 :             :         else
    6055                 :             :         {
    6056                 :           2 :                 value = 0;
    6057                 :           2 :                 isnull = true;
    6058                 :             :         }
    6059                 :             : 
    6060                 :          15 :         elmtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
    6061         [ +  - ]:          15 :         if (!OidIsValid(elmtype))
    6062   [ #  #  #  # ]:           0 :                 elog(ERROR, "could not determine data type of input");
    6063                 :             : 
    6064                 :          15 :         result = array_fill_internal(dims, NULL, value, isnull, elmtype, fcinfo);
    6065                 :          30 :         PG_RETURN_ARRAYTYPE_P(result);
    6066                 :          15 : }
    6067                 :             : 
    6068                 :             : static ArrayType *
    6069                 :          11 : create_array_envelope(int ndims, int *dimv, int *lbsv, int nbytes,
    6070                 :             :                                           Oid elmtype, int dataoffset)
    6071                 :             : {
    6072                 :          11 :         ArrayType  *result;
    6073                 :             : 
    6074                 :          11 :         result = (ArrayType *) palloc0(nbytes);
    6075                 :          11 :         SET_VARSIZE(result, nbytes);
    6076                 :          11 :         result->ndim = ndims;
    6077                 :          11 :         result->dataoffset = dataoffset;
    6078                 :          11 :         result->elemtype = elmtype;
    6079                 :          11 :         memcpy(ARR_DIMS(result), dimv, ndims * sizeof(int));
    6080                 :          11 :         memcpy(ARR_LBOUND(result), lbsv, ndims * sizeof(int));
    6081                 :             : 
    6082                 :          22 :         return result;
    6083                 :          11 : }
    6084                 :             : 
    6085                 :             : static ArrayType *
    6086                 :          24 : array_fill_internal(ArrayType *dims, ArrayType *lbs,
    6087                 :             :                                         Datum value, bool isnull, Oid elmtype,
    6088                 :             :                                         FunctionCallInfo fcinfo)
    6089                 :             : {
    6090                 :          24 :         ArrayType  *result;
    6091                 :          24 :         int                *dimv;
    6092                 :          24 :         int                *lbsv;
    6093                 :          24 :         int                     ndims;
    6094                 :          24 :         int                     nitems;
    6095                 :          24 :         int                     deflbs[MAXDIM];
    6096                 :          24 :         int16           elmlen;
    6097                 :          24 :         bool            elmbyval;
    6098                 :          24 :         char            elmalign;
    6099                 :          24 :         ArrayMetaState *my_extra;
    6100                 :             : 
    6101                 :             :         /*
    6102                 :             :          * Params checks
    6103                 :             :          */
    6104         [ +  + ]:          24 :         if (ARR_NDIM(dims) > 1)
    6105   [ +  -  +  - ]:           1 :                 ereport(ERROR,
    6106                 :             :                                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    6107                 :             :                                  errmsg("wrong number of array subscripts"),
    6108                 :             :                                  errdetail("Dimension array must be one dimensional.")));
    6109                 :             : 
    6110         [ +  + ]:          23 :         if (array_contains_nulls(dims))
    6111   [ +  -  +  - ]:           1 :                 ereport(ERROR,
    6112                 :             :                                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    6113                 :             :                                  errmsg("dimension values cannot be null")));
    6114                 :             : 
    6115         [ -  + ]:          22 :         dimv = (int *) ARR_DATA_PTR(dims);
    6116         [ +  + ]:          22 :         ndims = (ARR_NDIM(dims) > 0) ? ARR_DIMS(dims)[0] : 0;
    6117                 :             : 
    6118         [ +  - ]:          22 :         if (ndims < 0)                               /* we do allow zero-dimension arrays */
    6119   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    6120                 :             :                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    6121                 :             :                                  errmsg("invalid number of dimensions: %d", ndims)));
    6122         [ +  - ]:          22 :         if (ndims > MAXDIM)
    6123   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    6124                 :             :                                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    6125                 :             :                                  errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
    6126                 :             :                                                 ndims, MAXDIM)));
    6127                 :             : 
    6128         [ +  + ]:          22 :         if (lbs != NULL)
    6129                 :             :         {
    6130         [ +  - ]:           9 :                 if (ARR_NDIM(lbs) > 1)
    6131   [ #  #  #  # ]:           0 :                         ereport(ERROR,
    6132                 :             :                                         (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    6133                 :             :                                          errmsg("wrong number of array subscripts"),
    6134                 :             :                                          errdetail("Dimension array must be one dimensional.")));
    6135                 :             : 
    6136         [ +  - ]:           9 :                 if (array_contains_nulls(lbs))
    6137   [ #  #  #  # ]:           0 :                         ereport(ERROR,
    6138                 :             :                                         (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    6139                 :             :                                          errmsg("dimension values cannot be null")));
    6140                 :             : 
    6141   [ +  +  +  + ]:           9 :                 if (ndims != ((ARR_NDIM(lbs) > 0) ? ARR_DIMS(lbs)[0] : 0))
    6142   [ +  -  +  - ]:           2 :                         ereport(ERROR,
    6143                 :             :                                         (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    6144                 :             :                                          errmsg("wrong number of array subscripts"),
    6145                 :             :                                          errdetail("Low bound array has different size than dimensions array.")));
    6146                 :             : 
    6147         [ -  + ]:           7 :                 lbsv = (int *) ARR_DATA_PTR(lbs);
    6148                 :           7 :         }
    6149                 :             :         else
    6150                 :             :         {
    6151                 :          13 :                 int                     i;
    6152                 :             : 
    6153         [ +  + ]:          91 :                 for (i = 0; i < MAXDIM; i++)
    6154                 :          78 :                         deflbs[i] = 1;
    6155                 :             : 
    6156                 :          13 :                 lbsv = deflbs;
    6157                 :          13 :         }
    6158                 :             : 
    6159                 :             :         /* This checks for overflow of the array dimensions */
    6160                 :          20 :         nitems = ArrayGetNItems(ndims, dimv);
    6161                 :          20 :         ArrayCheckBounds(ndims, dimv, lbsv);
    6162                 :             : 
    6163                 :             :         /* fast track for empty array */
    6164         [ +  + ]:          20 :         if (nitems <= 0)
    6165                 :           9 :                 return construct_empty_array(elmtype);
    6166                 :             : 
    6167                 :             :         /*
    6168                 :             :          * We arrange to look up info about element type only once per series of
    6169                 :             :          * calls, assuming the element type doesn't change underneath us.
    6170                 :             :          */
    6171                 :          11 :         my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
    6172         [ -  + ]:          11 :         if (my_extra == NULL)
    6173                 :             :         {
    6174                 :          11 :                 fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
    6175                 :             :                                                                                                           sizeof(ArrayMetaState));
    6176                 :          11 :                 my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
    6177                 :          11 :                 my_extra->element_type = InvalidOid;
    6178                 :          11 :         }
    6179                 :             : 
    6180         [ -  + ]:          11 :         if (my_extra->element_type != elmtype)
    6181                 :             :         {
    6182                 :             :                 /* Get info about element type */
    6183                 :          22 :                 get_typlenbyvalalign(elmtype,
    6184                 :          11 :                                                          &my_extra->typlen,
    6185                 :          11 :                                                          &my_extra->typbyval,
    6186                 :          11 :                                                          &my_extra->typalign);
    6187                 :          11 :                 my_extra->element_type = elmtype;
    6188                 :          11 :         }
    6189                 :             : 
    6190                 :          11 :         elmlen = my_extra->typlen;
    6191                 :          11 :         elmbyval = my_extra->typbyval;
    6192                 :          11 :         elmalign = my_extra->typalign;
    6193                 :             : 
    6194                 :             :         /* compute required space */
    6195         [ +  + ]:          11 :         if (!isnull)
    6196                 :             :         {
    6197                 :           7 :                 int                     i;
    6198                 :           7 :                 char       *p;
    6199                 :           7 :                 int                     nbytes;
    6200                 :           7 :                 int                     totbytes;
    6201                 :             : 
    6202                 :             :                 /* make sure data is not toasted */
    6203         [ +  + ]:           7 :                 if (elmlen == -1)
    6204                 :           2 :                         value = PointerGetDatum(PG_DETOAST_DATUM(value));
    6205                 :             : 
    6206   [ +  +  +  -  :           7 :                 nbytes = att_addlength_datum(0, elmlen, value);
                   #  # ]
    6207   [ +  +  -  +  :           7 :                 nbytes = att_align_nominal(nbytes, elmalign);
             +  -  #  # ]
    6208         [ +  - ]:           7 :                 Assert(nbytes > 0);
    6209                 :             : 
    6210                 :           7 :                 totbytes = nbytes * nitems;
    6211                 :             : 
    6212                 :             :                 /* check for overflow of multiplication or total request */
    6213         [ +  - ]:           7 :                 if (totbytes / nbytes != nitems ||
    6214                 :           7 :                         !AllocSizeIsValid(totbytes))
    6215   [ #  #  #  # ]:           0 :                         ereport(ERROR,
    6216                 :             :                                         (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    6217                 :             :                                          errmsg("array size exceeds the maximum allowed (%zu)",
    6218                 :             :                                                         MaxAllocSize)));
    6219                 :             : 
    6220                 :             :                 /*
    6221                 :             :                  * This addition can't overflow, but it might cause us to go past
    6222                 :             :                  * MaxAllocSize.  We leave it to palloc to complain in that case.
    6223                 :             :                  */
    6224                 :           7 :                 totbytes += ARR_OVERHEAD_NONULLS(ndims);
    6225                 :             : 
    6226                 :          14 :                 result = create_array_envelope(ndims, dimv, lbsv, totbytes,
    6227                 :           7 :                                                                            elmtype, 0);
    6228                 :             : 
    6229         [ -  + ]:           7 :                 p = ARR_DATA_PTR(result);
    6230         [ +  + ]:      500051 :                 for (i = 0; i < nitems; i++)
    6231                 :      500044 :                         p += ArrayCastAndSet(value, elmlen, elmbyval, elmalign, p);
    6232                 :           7 :         }
    6233                 :             :         else
    6234                 :             :         {
    6235                 :           4 :                 int                     nbytes;
    6236                 :           4 :                 int                     dataoffset;
    6237                 :             : 
    6238                 :           4 :                 dataoffset = ARR_OVERHEAD_WITHNULLS(ndims, nitems);
    6239                 :           4 :                 nbytes = dataoffset;
    6240                 :             : 
    6241                 :           8 :                 result = create_array_envelope(ndims, dimv, lbsv, nbytes,
    6242                 :           4 :                                                                            elmtype, dataoffset);
    6243                 :             : 
    6244                 :             :                 /* create_array_envelope already zeroed the bitmap, so we're done */
    6245                 :           4 :         }
    6246                 :             : 
    6247                 :          11 :         return result;
    6248                 :          20 : }
    6249                 :             : 
    6250                 :             : 
    6251                 :             : /*
    6252                 :             :  * UNNEST
    6253                 :             :  */
    6254                 :             : Datum
    6255                 :       61861 : array_unnest(PG_FUNCTION_ARGS)
    6256                 :             : {
    6257                 :             :         typedef struct
    6258                 :             :         {
    6259                 :             :                 array_iter      iter;
    6260                 :             :                 int                     nextelem;
    6261                 :             :                 int                     numelems;
    6262                 :             :                 int16           elmlen;
    6263                 :             :                 bool            elmbyval;
    6264                 :             :                 char            elmalign;
    6265                 :             :         } array_unnest_fctx;
    6266                 :             : 
    6267                 :       61861 :         FuncCallContext *funcctx;
    6268                 :       61861 :         array_unnest_fctx *fctx;
    6269                 :       61861 :         MemoryContext oldcontext;
    6270                 :             : 
    6271                 :             :         /* stuff done only on the first call of the function */
    6272         [ +  + ]:       61861 :         if (SRF_IS_FIRSTCALL())
    6273                 :             :         {
    6274                 :        9981 :                 AnyArrayType *arr;
    6275                 :             : 
    6276                 :             :                 /* create a function context for cross-call persistence */
    6277                 :        9981 :                 funcctx = SRF_FIRSTCALL_INIT();
    6278                 :             : 
    6279                 :             :                 /*
    6280                 :             :                  * switch to memory context appropriate for multiple function calls
    6281                 :             :                  */
    6282                 :        9981 :                 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
    6283                 :             : 
    6284                 :             :                 /*
    6285                 :             :                  * Get the array value and detoast if needed.  We can't do this
    6286                 :             :                  * earlier because if we have to detoast, we want the detoasted copy
    6287                 :             :                  * to be in multi_call_memory_ctx, so it will go away when we're done
    6288                 :             :                  * and not before.  (If no detoast happens, we assume the originally
    6289                 :             :                  * passed array will stick around till then.)
    6290                 :             :                  */
    6291                 :        9981 :                 arr = PG_GETARG_ANY_ARRAY_P(0);
    6292                 :             : 
    6293                 :             :                 /* allocate memory for user context */
    6294                 :        9981 :                 fctx = palloc_object(array_unnest_fctx);
    6295                 :             : 
    6296                 :             :                 /* initialize state */
    6297                 :        9981 :                 array_iter_setup(&fctx->iter, arr);
    6298                 :        9981 :                 fctx->nextelem = 0;
    6299   [ +  -  +  - ]:        9981 :                 fctx->numelems = ArrayGetNItems(AARR_NDIM(arr), AARR_DIMS(arr));
    6300                 :             : 
    6301         [ +  - ]:        9981 :                 if (VARATT_IS_EXPANDED_HEADER(arr))
    6302                 :             :                 {
    6303                 :             :                         /* we can just grab the type data from expanded array */
    6304                 :           0 :                         fctx->elmlen = arr->xpn.typlen;
    6305                 :           0 :                         fctx->elmbyval = arr->xpn.typbyval;
    6306                 :           0 :                         fctx->elmalign = arr->xpn.typalign;
    6307                 :           0 :                 }
    6308                 :             :                 else
    6309         [ +  - ]:        9981 :                         get_typlenbyvalalign(AARR_ELEMTYPE(arr),
    6310                 :        9981 :                                                                  &fctx->elmlen,
    6311                 :        9981 :                                                                  &fctx->elmbyval,
    6312                 :        9981 :                                                                  &fctx->elmalign);
    6313                 :             : 
    6314                 :        9981 :                 funcctx->user_fctx = fctx;
    6315                 :        9981 :                 MemoryContextSwitchTo(oldcontext);
    6316                 :        9981 :         }
    6317                 :             : 
    6318                 :             :         /* stuff done on every call of the function */
    6319                 :       61861 :         funcctx = SRF_PERCALL_SETUP();
    6320                 :       61861 :         fctx = funcctx->user_fctx;
    6321                 :             : 
    6322         [ +  + ]:       61861 :         if (fctx->nextelem < fctx->numelems)
    6323                 :             :         {
    6324                 :       51880 :                 int                     offset = fctx->nextelem++;
    6325                 :       51880 :                 Datum           elem;
    6326                 :             : 
    6327                 :      103760 :                 elem = array_iter_next(&fctx->iter, &fcinfo->isnull, offset,
    6328                 :       51880 :                                                            fctx->elmlen, fctx->elmbyval, fctx->elmalign);
    6329                 :             : 
    6330                 :       51880 :                 SRF_RETURN_NEXT(funcctx, elem);
    6331         [ +  - ]:       51880 :         }
    6332                 :             :         else
    6333                 :             :         {
    6334                 :             :                 /* do when there is no more left */
    6335         [ +  - ]:        9981 :                 SRF_RETURN_DONE(funcctx);
    6336                 :             :         }
    6337         [ -  + ]:       61861 : }
    6338                 :             : 
    6339                 :             : /*
    6340                 :             :  * Planner support function for array_unnest(anyarray)
    6341                 :             :  *
    6342                 :             :  * Note: this is now also used for information_schema._pg_expandarray(),
    6343                 :             :  * which is simply a wrapper around array_unnest().
    6344                 :             :  */
    6345                 :             : Datum
    6346                 :        1765 : array_unnest_support(PG_FUNCTION_ARGS)
    6347                 :             : {
    6348                 :        1765 :         Node       *rawreq = (Node *) PG_GETARG_POINTER(0);
    6349                 :        1765 :         Node       *ret = NULL;
    6350                 :             : 
    6351         [ +  + ]:        1765 :         if (IsA(rawreq, SupportRequestRows))
    6352                 :             :         {
    6353                 :             :                 /* Try to estimate the number of rows returned */
    6354                 :         473 :                 SupportRequestRows *req = (SupportRequestRows *) rawreq;
    6355                 :             : 
    6356         [ +  + ]:         473 :                 if (is_funcclause(req->node))        /* be paranoid */
    6357                 :             :                 {
    6358                 :         472 :                         List       *args = ((FuncExpr *) req->node)->args;
    6359                 :         472 :                         Node       *arg1;
    6360                 :             : 
    6361                 :             :                         /* We can use estimated argument values here */
    6362                 :         472 :                         arg1 = estimate_expression_value(req->root, linitial(args));
    6363                 :             : 
    6364                 :         472 :                         req->rows = estimate_array_length(req->root, arg1);
    6365                 :         472 :                         ret = (Node *) req;
    6366                 :         472 :                 }
    6367                 :         473 :         }
    6368                 :             : 
    6369                 :        3530 :         PG_RETURN_POINTER(ret);
    6370                 :        1765 : }
    6371                 :             : 
    6372                 :             : 
    6373                 :             : /*
    6374                 :             :  * array_replace/array_remove support
    6375                 :             :  *
    6376                 :             :  * Find all array entries matching (not distinct from) search/search_isnull,
    6377                 :             :  * and delete them if remove is true, else replace them with
    6378                 :             :  * replace/replace_isnull.  Comparisons are done using the specified
    6379                 :             :  * collation.  fcinfo is passed only for caching purposes.
    6380                 :             :  */
    6381                 :             : static ArrayType *
    6382                 :          13 : array_replace_internal(ArrayType *array,
    6383                 :             :                                            Datum search, bool search_isnull,
    6384                 :             :                                            Datum replace, bool replace_isnull,
    6385                 :             :                                            bool remove, Oid collation,
    6386                 :             :                                            FunctionCallInfo fcinfo)
    6387                 :             : {
    6388                 :          13 :         LOCAL_FCINFO(locfcinfo, 2);
    6389                 :          13 :         ArrayType  *result;
    6390                 :          13 :         Oid                     element_type;
    6391                 :          13 :         Datum      *values;
    6392                 :          13 :         bool       *nulls;
    6393                 :          13 :         int                *dim;
    6394                 :          13 :         int                     ndim;
    6395                 :          13 :         int                     nitems,
    6396                 :             :                                 nresult;
    6397                 :          13 :         int                     i;
    6398                 :          13 :         int32           nbytes = 0;
    6399                 :          13 :         int32           dataoffset;
    6400                 :          13 :         bool            hasnulls;
    6401                 :          13 :         int                     typlen;
    6402                 :          13 :         bool            typbyval;
    6403                 :          13 :         char            typalign;
    6404                 :          13 :         char       *arraydataptr;
    6405                 :          13 :         bits8      *bitmap;
    6406                 :          13 :         int                     bitmask;
    6407                 :          13 :         bool            changed = false;
    6408                 :          13 :         TypeCacheEntry *typentry;
    6409                 :             : 
    6410                 :          13 :         element_type = ARR_ELEMTYPE(array);
    6411                 :          13 :         ndim = ARR_NDIM(array);
    6412                 :          13 :         dim = ARR_DIMS(array);
    6413                 :          13 :         nitems = ArrayGetNItems(ndim, dim);
    6414                 :             : 
    6415                 :             :         /* Return input array unmodified if it is empty */
    6416         [ -  + ]:          13 :         if (nitems <= 0)
    6417                 :           0 :                 return array;
    6418                 :             : 
    6419                 :             :         /*
    6420                 :             :          * We can't remove elements from multi-dimensional arrays, since the
    6421                 :             :          * result might not be rectangular.
    6422                 :             :          */
    6423   [ +  +  +  + ]:          13 :         if (remove && ndim > 1)
    6424   [ +  -  +  - ]:           1 :                 ereport(ERROR,
    6425                 :             :                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    6426                 :             :                                  errmsg("removing elements from multidimensional arrays is not supported")));
    6427                 :             : 
    6428                 :             :         /*
    6429                 :             :          * We arrange to look up the equality function only once per series of
    6430                 :             :          * calls, assuming the element type doesn't change underneath us.
    6431                 :             :          */
    6432                 :          12 :         typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
    6433   [ -  +  #  # ]:          12 :         if (typentry == NULL ||
    6434                 :           0 :                 typentry->type_id != element_type)
    6435                 :             :         {
    6436                 :          12 :                 typentry = lookup_type_cache(element_type,
    6437                 :             :                                                                          TYPECACHE_EQ_OPR_FINFO);
    6438         [ +  - ]:          12 :                 if (!OidIsValid(typentry->eq_opr_finfo.fn_oid))
    6439   [ #  #  #  # ]:           0 :                         ereport(ERROR,
    6440                 :             :                                         (errcode(ERRCODE_UNDEFINED_FUNCTION),
    6441                 :             :                                          errmsg("could not identify an equality operator for type %s",
    6442                 :             :                                                         format_type_be(element_type))));
    6443                 :          12 :                 fcinfo->flinfo->fn_extra = typentry;
    6444                 :          12 :         }
    6445                 :          12 :         typlen = typentry->typlen;
    6446                 :          12 :         typbyval = typentry->typbyval;
    6447                 :          12 :         typalign = typentry->typalign;
    6448                 :             : 
    6449                 :             :         /*
    6450                 :             :          * Detoast values if they are toasted.  The replacement value must be
    6451                 :             :          * detoasted for insertion into the result array, while detoasting the
    6452                 :             :          * search value only once saves cycles.
    6453                 :             :          */
    6454         [ +  + ]:          12 :         if (typlen == -1)
    6455                 :             :         {
    6456         [ +  + ]:           5 :                 if (!search_isnull)
    6457                 :           4 :                         search = PointerGetDatum(PG_DETOAST_DATUM(search));
    6458         [ +  + ]:           5 :                 if (!replace_isnull)
    6459                 :           2 :                         replace = PointerGetDatum(PG_DETOAST_DATUM(replace));
    6460                 :           5 :         }
    6461                 :             : 
    6462                 :             :         /* Prepare to apply the comparison operator */
    6463                 :          12 :         InitFunctionCallInfoData(*locfcinfo, &typentry->eq_opr_finfo, 2,
    6464                 :             :                                                          collation, NULL, NULL);
    6465                 :             : 
    6466                 :             :         /* Allocate temporary arrays for new values */
    6467                 :          12 :         values = (Datum *) palloc(nitems * sizeof(Datum));
    6468                 :          12 :         nulls = (bool *) palloc(nitems * sizeof(bool));
    6469                 :             : 
    6470                 :             :         /* Loop over source data */
    6471         [ +  + ]:          12 :         arraydataptr = ARR_DATA_PTR(array);
    6472         [ +  + ]:          12 :         bitmap = ARR_NULLBITMAP(array);
    6473                 :          12 :         bitmask = 1;
    6474                 :          12 :         hasnulls = false;
    6475                 :          12 :         nresult = 0;
    6476                 :             : 
    6477         [ +  + ]:          58 :         for (i = 0; i < nitems; i++)
    6478                 :             :         {
    6479                 :          46 :                 Datum           elt;
    6480                 :          46 :                 bool            isNull;
    6481                 :          46 :                 bool            oprresult;
    6482                 :          46 :                 bool            skip = false;
    6483                 :             : 
    6484                 :             :                 /* Get source element, checking for NULL */
    6485   [ +  +  +  + ]:          46 :                 if (bitmap && (*bitmap & bitmask) == 0)
    6486                 :             :                 {
    6487                 :           6 :                         isNull = true;
    6488                 :             :                         /* If searching for NULL, we have a match */
    6489         [ -  + ]:           6 :                         if (search_isnull)
    6490                 :             :                         {
    6491         [ +  + ]:           6 :                                 if (remove)
    6492                 :             :                                 {
    6493                 :           2 :                                         skip = true;
    6494                 :           2 :                                         changed = true;
    6495                 :           2 :                                 }
    6496         [ +  + ]:           4 :                                 else if (!replace_isnull)
    6497                 :             :                                 {
    6498                 :           3 :                                         values[nresult] = replace;
    6499                 :           3 :                                         isNull = false;
    6500                 :           3 :                                         changed = true;
    6501                 :           3 :                                 }
    6502                 :           6 :                         }
    6503                 :           6 :                 }
    6504                 :             :                 else
    6505                 :             :                 {
    6506                 :          40 :                         isNull = false;
    6507                 :          40 :                         elt = fetch_att(arraydataptr, typbyval, typlen);
    6508   [ +  +  -  +  :          40 :                         arraydataptr = att_addlength_datum(arraydataptr, typlen, elt);
                   #  # ]
    6509   [ +  -  #  #  :          40 :                         arraydataptr = (char *) att_align_nominal(arraydataptr, typalign);
             #  #  #  # ]
    6510                 :             : 
    6511         [ +  + ]:          40 :                         if (search_isnull)
    6512                 :             :                         {
    6513                 :             :                                 /* no match possible, keep element */
    6514                 :           9 :                                 values[nresult] = elt;
    6515                 :           9 :                         }
    6516                 :             :                         else
    6517                 :             :                         {
    6518                 :             :                                 /*
    6519                 :             :                                  * Apply the operator to the element pair; treat NULL as false
    6520                 :             :                                  */
    6521                 :          31 :                                 locfcinfo->args[0].value = elt;
    6522                 :          31 :                                 locfcinfo->args[0].isnull = false;
    6523                 :          31 :                                 locfcinfo->args[1].value = search;
    6524                 :          31 :                                 locfcinfo->args[1].isnull = false;
    6525                 :          31 :                                 locfcinfo->isnull = false;
    6526                 :          31 :                                 oprresult = DatumGetBool(FunctionCallInvoke(locfcinfo));
    6527   [ +  -  +  + ]:          31 :                                 if (locfcinfo->isnull || !oprresult)
    6528                 :             :                                 {
    6529                 :             :                                         /* no match, keep element */
    6530                 :          20 :                                         values[nresult] = elt;
    6531                 :          20 :                                 }
    6532                 :             :                                 else
    6533                 :             :                                 {
    6534                 :             :                                         /* match, so replace or delete */
    6535                 :          11 :                                         changed = true;
    6536         [ +  + ]:          11 :                                         if (remove)
    6537                 :           7 :                                                 skip = true;
    6538                 :             :                                         else
    6539                 :             :                                         {
    6540                 :           4 :                                                 values[nresult] = replace;
    6541                 :           4 :                                                 isNull = replace_isnull;
    6542                 :             :                                         }
    6543                 :             :                                 }
    6544                 :             :                         }
    6545                 :             :                 }
    6546                 :             : 
    6547         [ +  + ]:          46 :                 if (!skip)
    6548                 :             :                 {
    6549                 :          37 :                         nulls[nresult] = isNull;
    6550         [ +  + ]:          37 :                         if (isNull)
    6551                 :           2 :                                 hasnulls = true;
    6552                 :             :                         else
    6553                 :             :                         {
    6554                 :             :                                 /* Update total result size */
    6555   [ +  +  -  +  :          35 :                                 nbytes = att_addlength_datum(nbytes, typlen, values[nresult]);
                   #  # ]
    6556   [ +  -  #  #  :          35 :                                 nbytes = att_align_nominal(nbytes, typalign);
             #  #  #  # ]
    6557                 :             :                                 /* check for overflow of total request */
    6558         [ +  - ]:          35 :                                 if (!AllocSizeIsValid(nbytes))
    6559   [ #  #  #  # ]:           0 :                                         ereport(ERROR,
    6560                 :             :                                                         (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    6561                 :             :                                                          errmsg("array size exceeds the maximum allowed (%zu)",
    6562                 :             :                                                                         MaxAllocSize)));
    6563                 :             :                         }
    6564                 :          37 :                         nresult++;
    6565                 :          37 :                 }
    6566                 :             : 
    6567                 :             :                 /* advance bitmap pointer if any */
    6568         [ +  + ]:          46 :                 if (bitmap)
    6569                 :             :                 {
    6570                 :          15 :                         bitmask <<= 1;
    6571         [ +  - ]:          15 :                         if (bitmask == 0x100)
    6572                 :             :                         {
    6573                 :           0 :                                 bitmap++;
    6574                 :           0 :                                 bitmask = 1;
    6575                 :           0 :                         }
    6576                 :          15 :                 }
    6577                 :          46 :         }
    6578                 :             : 
    6579                 :             :         /*
    6580                 :             :          * If not changed just return the original array
    6581                 :             :          */
    6582         [ +  + ]:          12 :         if (!changed)
    6583                 :             :         {
    6584                 :           2 :                 pfree(values);
    6585                 :           2 :                 pfree(nulls);
    6586                 :           2 :                 return array;
    6587                 :             :         }
    6588                 :             : 
    6589                 :             :         /* If all elements were removed return an empty array */
    6590         [ +  + ]:          10 :         if (nresult == 0)
    6591                 :             :         {
    6592                 :           1 :                 pfree(values);
    6593                 :           1 :                 pfree(nulls);
    6594                 :           1 :                 return construct_empty_array(element_type);
    6595                 :             :         }
    6596                 :             : 
    6597                 :             :         /* Allocate and initialize the result array */
    6598         [ +  + ]:           9 :         if (hasnulls)
    6599                 :             :         {
    6600                 :           1 :                 dataoffset = ARR_OVERHEAD_WITHNULLS(ndim, nresult);
    6601                 :           1 :                 nbytes += dataoffset;
    6602                 :           1 :         }
    6603                 :             :         else
    6604                 :             :         {
    6605                 :           8 :                 dataoffset = 0;                 /* marker for no null bitmap */
    6606                 :           8 :                 nbytes += ARR_OVERHEAD_NONULLS(ndim);
    6607                 :             :         }
    6608                 :           9 :         result = (ArrayType *) palloc0(nbytes);
    6609                 :           9 :         SET_VARSIZE(result, nbytes);
    6610                 :           9 :         result->ndim = ndim;
    6611                 :           9 :         result->dataoffset = dataoffset;
    6612                 :           9 :         result->elemtype = element_type;
    6613                 :           9 :         memcpy(ARR_DIMS(result), ARR_DIMS(array), ndim * sizeof(int));
    6614                 :           9 :         memcpy(ARR_LBOUND(result), ARR_LBOUND(array), ndim * sizeof(int));
    6615                 :             : 
    6616         [ +  + ]:           9 :         if (remove)
    6617                 :             :         {
    6618                 :             :                 /* Adjust the result length */
    6619                 :           4 :                 ARR_DIMS(result)[0] = nresult;
    6620                 :           4 :         }
    6621                 :             : 
    6622                 :             :         /* Insert data into result array */
    6623                 :          18 :         CopyArrayEls(result,
    6624                 :           9 :                                  values, nulls, nresult,
    6625                 :           9 :                                  typlen, typbyval, typalign,
    6626                 :             :                                  false);
    6627                 :             : 
    6628                 :           9 :         pfree(values);
    6629                 :           9 :         pfree(nulls);
    6630                 :             : 
    6631                 :           9 :         return result;
    6632                 :          12 : }
    6633                 :             : 
    6634                 :             : /*
    6635                 :             :  * Remove any occurrences of an element from an array
    6636                 :             :  *
    6637                 :             :  * If used on a multi-dimensional array this will raise an error.
    6638                 :             :  */
    6639                 :             : Datum
    6640                 :          49 : array_remove(PG_FUNCTION_ARGS)
    6641                 :             : {
    6642                 :          49 :         ArrayType  *array;
    6643                 :          49 :         Datum           search = PG_GETARG_DATUM(1);
    6644                 :          49 :         bool            search_isnull = PG_ARGISNULL(1);
    6645                 :             : 
    6646         [ +  + ]:          49 :         if (PG_ARGISNULL(0))
    6647                 :          42 :                 PG_RETURN_NULL();
    6648                 :           7 :         array = PG_GETARG_ARRAYTYPE_P(0);
    6649                 :             : 
    6650                 :          14 :         array = array_replace_internal(array,
    6651                 :           7 :                                                                    search, search_isnull,
    6652                 :             :                                                                    (Datum) 0, true,
    6653                 :           7 :                                                                    true, PG_GET_COLLATION(),
    6654                 :           7 :                                                                    fcinfo);
    6655                 :           7 :         PG_RETURN_ARRAYTYPE_P(array);
    6656                 :          49 : }
    6657                 :             : 
    6658                 :             : /*
    6659                 :             :  * Replace any occurrences of an element in an array
    6660                 :             :  */
    6661                 :             : Datum
    6662                 :           6 : array_replace(PG_FUNCTION_ARGS)
    6663                 :             : {
    6664                 :           6 :         ArrayType  *array;
    6665                 :           6 :         Datum           search = PG_GETARG_DATUM(1);
    6666                 :           6 :         bool            search_isnull = PG_ARGISNULL(1);
    6667                 :           6 :         Datum           replace = PG_GETARG_DATUM(2);
    6668                 :           6 :         bool            replace_isnull = PG_ARGISNULL(2);
    6669                 :             : 
    6670         [ +  - ]:           6 :         if (PG_ARGISNULL(0))
    6671                 :           0 :                 PG_RETURN_NULL();
    6672                 :           6 :         array = PG_GETARG_ARRAYTYPE_P(0);
    6673                 :             : 
    6674                 :          12 :         array = array_replace_internal(array,
    6675                 :           6 :                                                                    search, search_isnull,
    6676                 :           6 :                                                                    replace, replace_isnull,
    6677                 :           6 :                                                                    false, PG_GET_COLLATION(),
    6678                 :           6 :                                                                    fcinfo);
    6679                 :           6 :         PG_RETURN_ARRAYTYPE_P(array);
    6680                 :           6 : }
    6681                 :             : 
    6682                 :             : /*
    6683                 :             :  * Implements width_bucket(anyelement, anyarray).
    6684                 :             :  *
    6685                 :             :  * 'thresholds' is an array containing lower bound values for each bucket;
    6686                 :             :  * these must be sorted from smallest to largest, or bogus results will be
    6687                 :             :  * produced.  If N thresholds are supplied, the output is from 0 to N:
    6688                 :             :  * 0 is for inputs < first threshold, N is for inputs >= last threshold.
    6689                 :             :  */
    6690                 :             : Datum
    6691                 :         135 : width_bucket_array(PG_FUNCTION_ARGS)
    6692                 :             : {
    6693                 :         135 :         Datum           operand = PG_GETARG_DATUM(0);
    6694                 :         135 :         ArrayType  *thresholds = PG_GETARG_ARRAYTYPE_P(1);
    6695                 :         135 :         Oid                     collation = PG_GET_COLLATION();
    6696                 :         135 :         Oid                     element_type = ARR_ELEMTYPE(thresholds);
    6697                 :         135 :         int                     result;
    6698                 :             : 
    6699                 :             :         /* Check input */
    6700         [ +  + ]:         135 :         if (ARR_NDIM(thresholds) > 1)
    6701   [ +  -  +  - ]:           1 :                 ereport(ERROR,
    6702                 :             :                                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    6703                 :             :                                  errmsg("thresholds must be one-dimensional array")));
    6704                 :             : 
    6705         [ +  + ]:         134 :         if (array_contains_nulls(thresholds))
    6706   [ +  -  +  - ]:           1 :                 ereport(ERROR,
    6707                 :             :                                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    6708                 :             :                                  errmsg("thresholds array must not contain NULLs")));
    6709                 :             : 
    6710                 :             :         /* We have a dedicated implementation for float8 data */
    6711         [ +  + ]:         133 :         if (element_type == FLOAT8OID)
    6712                 :          61 :                 result = width_bucket_array_float8(operand, thresholds);
    6713                 :             :         else
    6714                 :             :         {
    6715                 :          72 :                 TypeCacheEntry *typentry;
    6716                 :             : 
    6717                 :             :                 /* Cache information about the input type */
    6718                 :          72 :                 typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
    6719   [ +  +  -  + ]:          72 :                 if (typentry == NULL ||
    6720                 :          65 :                         typentry->type_id != element_type)
    6721                 :             :                 {
    6722                 :           7 :                         typentry = lookup_type_cache(element_type,
    6723                 :             :                                                                                  TYPECACHE_CMP_PROC_FINFO);
    6724         [ +  - ]:           7 :                         if (!OidIsValid(typentry->cmp_proc_finfo.fn_oid))
    6725   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
    6726                 :             :                                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
    6727                 :             :                                                  errmsg("could not identify a comparison function for type %s",
    6728                 :             :                                                                 format_type_be(element_type))));
    6729                 :           7 :                         fcinfo->flinfo->fn_extra = typentry;
    6730                 :           7 :                 }
    6731                 :             : 
    6732                 :             :                 /*
    6733                 :             :                  * We have separate implementation paths for fixed- and variable-width
    6734                 :             :                  * types, since indexing the array is a lot cheaper in the first case.
    6735                 :             :                  */
    6736         [ +  + ]:          72 :                 if (typentry->typlen > 0)
    6737                 :          30 :                         result = width_bucket_array_fixed(operand, thresholds,
    6738                 :          15 :                                                                                           collation, typentry);
    6739                 :             :                 else
    6740                 :         114 :                         result = width_bucket_array_variable(operand, thresholds,
    6741                 :          57 :                                                                                                  collation, typentry);
    6742                 :          72 :         }
    6743                 :             : 
    6744                 :             :         /* Avoid leaking memory when handed toasted input. */
    6745         [ +  - ]:         133 :         PG_FREE_IF_COPY(thresholds, 1);
    6746                 :             : 
    6747                 :         266 :         PG_RETURN_INT32(result);
    6748                 :         133 : }
    6749                 :             : 
    6750                 :             : /*
    6751                 :             :  * width_bucket_array for float8 data.
    6752                 :             :  */
    6753                 :             : static int
    6754                 :          61 : width_bucket_array_float8(Datum operand, ArrayType *thresholds)
    6755                 :             : {
    6756                 :          61 :         float8          op = DatumGetFloat8(operand);
    6757                 :          61 :         float8     *thresholds_data;
    6758                 :          61 :         int                     left;
    6759                 :          61 :         int                     right;
    6760                 :             : 
    6761                 :             :         /*
    6762                 :             :          * Since we know the array contains no NULLs, we can just index it
    6763                 :             :          * directly.
    6764                 :             :          */
    6765         [ +  - ]:          61 :         thresholds_data = (float8 *) ARR_DATA_PTR(thresholds);
    6766                 :             : 
    6767                 :          61 :         left = 0;
    6768                 :          61 :         right = ArrayGetNItems(ARR_NDIM(thresholds), ARR_DIMS(thresholds));
    6769                 :             : 
    6770                 :             :         /*
    6771                 :             :          * If the probe value is a NaN, it's greater than or equal to all possible
    6772                 :             :          * threshold values (including other NaNs), so we need not search.  Note
    6773                 :             :          * that this would give the same result as searching even if the array
    6774                 :             :          * contains multiple NaNs (as long as they're correctly sorted), since the
    6775                 :             :          * loop logic will find the rightmost of multiple equal threshold values.
    6776                 :             :          */
    6777   [ -  +  +  +  :          61 :         if (isnan(op))
                   +  - ]
    6778                 :         147 :                 return right;
    6779                 :             : 
    6780                 :             :         /* Find the bucket */
    6781         [ +  + ]:         361 :         while (left < right)
    6782                 :             :         {
    6783                 :         129 :                 int                     mid = (left + right) / 2;
    6784                 :             : 
    6785   [ -  +  +  +  :         129 :                 if (isnan(thresholds_data[mid]) || op < thresholds_data[mid])
                   +  - ]
    6786                 :         202 :                         right = mid;
    6787                 :             :                 else
    6788                 :          73 :                         left = mid + 1;
    6789                 :         275 :         }
    6790                 :             : 
    6791                 :          60 :         return left;
    6792                 :         207 : }
    6793                 :             : 
    6794                 :             : /*
    6795                 :             :  * width_bucket_array for generic fixed-width data types.
    6796                 :             :  */
    6797                 :             : static int
    6798                 :          15 : width_bucket_array_fixed(Datum operand,
    6799                 :             :                                                  ArrayType *thresholds,
    6800                 :             :                                                  Oid collation,
    6801                 :             :                                                  TypeCacheEntry *typentry)
    6802                 :             : {
    6803                 :          15 :         LOCAL_FCINFO(locfcinfo, 2);
    6804                 :          15 :         char       *thresholds_data;
    6805                 :          15 :         int                     typlen = typentry->typlen;
    6806                 :          15 :         bool            typbyval = typentry->typbyval;
    6807                 :          15 :         int                     left;
    6808                 :          15 :         int                     right;
    6809                 :             : 
    6810                 :             :         /*
    6811                 :             :          * Since we know the array contains no NULLs, we can just index it
    6812                 :             :          * directly.
    6813                 :             :          */
    6814         [ -  + ]:          15 :         thresholds_data = (char *) ARR_DATA_PTR(thresholds);
    6815                 :             : 
    6816                 :          15 :         InitFunctionCallInfoData(*locfcinfo, &typentry->cmp_proc_finfo, 2,
    6817                 :             :                                                          collation, NULL, NULL);
    6818                 :             : 
    6819                 :             :         /* Find the bucket */
    6820                 :          15 :         left = 0;
    6821                 :          15 :         right = ArrayGetNItems(ARR_NDIM(thresholds), ARR_DIMS(thresholds));
    6822         [ +  + ]:          45 :         while (left < right)
    6823                 :             :         {
    6824                 :          30 :                 int                     mid = (left + right) / 2;
    6825                 :          30 :                 char       *ptr;
    6826                 :          30 :                 int32           cmpresult;
    6827                 :             : 
    6828                 :          30 :                 ptr = thresholds_data + mid * typlen;
    6829                 :             : 
    6830                 :          30 :                 locfcinfo->args[0].value = operand;
    6831                 :          30 :                 locfcinfo->args[0].isnull = false;
    6832                 :          30 :                 locfcinfo->args[1].value = fetch_att(ptr, typbyval, typlen);
    6833                 :          30 :                 locfcinfo->args[1].isnull = false;
    6834                 :             : 
    6835                 :          30 :                 cmpresult = DatumGetInt32(FunctionCallInvoke(locfcinfo));
    6836                 :             : 
    6837                 :             :                 /* We don't expect comparison support functions to return null */
    6838         [ +  - ]:          30 :                 Assert(!locfcinfo->isnull);
    6839                 :             : 
    6840         [ +  + ]:          30 :                 if (cmpresult < 0)
    6841                 :          15 :                         right = mid;
    6842                 :             :                 else
    6843                 :          15 :                         left = mid + 1;
    6844                 :          30 :         }
    6845                 :             : 
    6846                 :          30 :         return left;
    6847                 :          15 : }
    6848                 :             : 
    6849                 :             : /*
    6850                 :             :  * width_bucket_array for generic variable-width data types.
    6851                 :             :  */
    6852                 :             : static int
    6853                 :          57 : width_bucket_array_variable(Datum operand,
    6854                 :             :                                                         ArrayType *thresholds,
    6855                 :             :                                                         Oid collation,
    6856                 :             :                                                         TypeCacheEntry *typentry)
    6857                 :             : {
    6858                 :          57 :         LOCAL_FCINFO(locfcinfo, 2);
    6859                 :          57 :         char       *thresholds_data;
    6860                 :          57 :         int                     typlen = typentry->typlen;
    6861                 :          57 :         bool            typbyval = typentry->typbyval;
    6862                 :          57 :         char            typalign = typentry->typalign;
    6863                 :          57 :         int                     left;
    6864                 :          57 :         int                     right;
    6865                 :             : 
    6866         [ -  + ]:          57 :         thresholds_data = (char *) ARR_DATA_PTR(thresholds);
    6867                 :             : 
    6868                 :          57 :         InitFunctionCallInfoData(*locfcinfo, &typentry->cmp_proc_finfo, 2,
    6869                 :             :                                                          collation, NULL, NULL);
    6870                 :             : 
    6871                 :             :         /* Find the bucket */
    6872                 :          57 :         left = 0;
    6873                 :          57 :         right = ArrayGetNItems(ARR_NDIM(thresholds), ARR_DIMS(thresholds));
    6874         [ +  + ]:         178 :         while (left < right)
    6875                 :             :         {
    6876                 :         121 :                 int                     mid = (left + right) / 2;
    6877                 :         121 :                 char       *ptr;
    6878                 :         121 :                 int                     i;
    6879                 :         121 :                 int32           cmpresult;
    6880                 :             : 
    6881                 :             :                 /* Locate mid'th array element by advancing from left element */
    6882                 :         121 :                 ptr = thresholds_data;
    6883         [ +  + ]:         207 :                 for (i = left; i < mid; i++)
    6884                 :             :                 {
    6885   [ -  +  -  +  :          86 :                         ptr = att_addlength_pointer(ptr, typlen, ptr);
                   #  # ]
    6886   [ +  -  #  #  :          86 :                         ptr = (char *) att_align_nominal(ptr, typalign);
             #  #  #  # ]
    6887                 :          86 :                 }
    6888                 :             : 
    6889                 :         121 :                 locfcinfo->args[0].value = operand;
    6890                 :         121 :                 locfcinfo->args[0].isnull = false;
    6891                 :         121 :                 locfcinfo->args[1].value = fetch_att(ptr, typbyval, typlen);
    6892                 :         121 :                 locfcinfo->args[1].isnull = false;
    6893                 :             : 
    6894                 :         121 :                 cmpresult = DatumGetInt32(FunctionCallInvoke(locfcinfo));
    6895                 :             : 
    6896                 :             :                 /* We don't expect comparison support functions to return null */
    6897         [ -  + ]:         121 :                 Assert(!locfcinfo->isnull);
    6898                 :             : 
    6899         [ +  + ]:         121 :                 if (cmpresult < 0)
    6900                 :          50 :                         right = mid;
    6901                 :             :                 else
    6902                 :             :                 {
    6903                 :          71 :                         left = mid + 1;
    6904                 :             : 
    6905                 :             :                         /*
    6906                 :             :                          * Move the thresholds pointer to match new "left" index, so we
    6907                 :             :                          * don't have to seek over those elements again.  This trick
    6908                 :             :                          * ensures we do only O(N) array indexing work, not O(N^2).
    6909                 :             :                          */
    6910   [ -  +  +  -  :          71 :                         ptr = att_addlength_pointer(ptr, typlen, ptr);
                   #  # ]
    6911   [ +  -  #  #  :          71 :                         thresholds_data = (char *) att_align_nominal(ptr, typalign);
             #  #  #  # ]
    6912                 :             :                 }
    6913                 :         121 :         }
    6914                 :             : 
    6915                 :         114 :         return left;
    6916                 :          57 : }
    6917                 :             : 
    6918                 :             : /*
    6919                 :             :  * Trim the last N elements from an array by building an appropriate slice.
    6920                 :             :  * Only the first dimension is trimmed.
    6921                 :             :  */
    6922                 :             : Datum
    6923                 :           8 : trim_array(PG_FUNCTION_ARGS)
    6924                 :             : {
    6925                 :           8 :         ArrayType  *v = PG_GETARG_ARRAYTYPE_P(0);
    6926                 :           8 :         int                     n = PG_GETARG_INT32(1);
    6927         [ +  + ]:           8 :         int                     array_length = (ARR_NDIM(v) > 0) ? ARR_DIMS(v)[0] : 0;
    6928                 :           8 :         int16           elmlen;
    6929                 :           8 :         bool            elmbyval;
    6930                 :           8 :         char            elmalign;
    6931                 :           8 :         int                     lower[MAXDIM];
    6932                 :           8 :         int                     upper[MAXDIM];
    6933                 :           8 :         bool            lowerProvided[MAXDIM];
    6934                 :           8 :         bool            upperProvided[MAXDIM];
    6935                 :           8 :         Datum           result;
    6936                 :             : 
    6937                 :             :         /* Per spec, throw an error if out of bounds */
    6938         [ +  + ]:           8 :         if (n < 0 || n > array_length)
    6939   [ +  -  +  - ]:           3 :                 ereport(ERROR,
    6940                 :             :                                 (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
    6941                 :             :                                  errmsg("number of elements to trim must be between 0 and %d",
    6942                 :             :                                                 array_length)));
    6943                 :             : 
    6944                 :             :         /* Set all the bounds as unprovided except the first upper bound */
    6945                 :           5 :         memset(lowerProvided, false, sizeof(lowerProvided));
    6946                 :           5 :         memset(upperProvided, false, sizeof(upperProvided));
    6947         [ -  + ]:           5 :         if (ARR_NDIM(v) > 0)
    6948                 :             :         {
    6949                 :           5 :                 upper[0] = ARR_LBOUND(v)[0] + array_length - n - 1;
    6950                 :           5 :                 upperProvided[0] = true;
    6951                 :           5 :         }
    6952                 :             : 
    6953                 :             :         /* Fetch the needed information about the element type */
    6954                 :           5 :         get_typlenbyvalalign(ARR_ELEMTYPE(v), &elmlen, &elmbyval, &elmalign);
    6955                 :             : 
    6956                 :             :         /* Get the slice */
    6957                 :          10 :         result = array_get_slice(PointerGetDatum(v), 1,
    6958                 :           5 :                                                          upper, lower, upperProvided, lowerProvided,
    6959                 :           5 :                                                          -1, elmlen, elmbyval, elmalign);
    6960                 :             : 
    6961                 :          10 :         PG_RETURN_DATUM(result);
    6962                 :           5 : }
        

Generated by: LCOV version 2.3.2-1