LCOV - differential code coverage report
Current view: top level - src/backend/utils/adt - arrayfuncs.c (source / functions) Coverage Total Hit UNC UBC GBC GIC GNC CBC DUB DCB
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 93.8 % 2369 2221 15 133 3 218 2000 20 255
Current Date: 2024-04-14 14:21:10 Functions: 100.0 % 90 90 9 81 3
Baseline: 16@8cea358b128 Branches: 65.4 % 2245 1469 62 714 5 2 156 1306
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed (60,120] days: 100.0 % 1 1 1
(120,180] days: 93.3 % 253 236 14 3 1 213 22
(240..) days: 93.8 % 2115 1984 1 130 2 4 1978
Function coverage date bins:
(120,180] days: 100.0 % 4 4 4
(240..) days: 100.0 % 86 86 5 81
Branch coverage date bins:
(120,180] days: 69.4 % 258 179 58 21 154 25
(240..) days: 64.9 % 1987 1290 4 693 5 2 2 1281

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

Generated by: LCOV version 2.1-beta2-3-g6141622