LCOV - differential code coverage report
Current view: top level - src/backend/utils/adt - arrayfuncs.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 93.7 % 2402 2250 27 45 78 2 51 1335 123 741 97 1450 2 14
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 89 89 85 4 89
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

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

Generated by: LCOV version v1.16-55-g56c0a2a