LCOV - differential code coverage report
Current view: top level - src/backend/utils/adt - arrayfuncs.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 93.7 % 2402 2250 27 45 78 2 51 1335 123 741 97 1450 2 14
Current Date: 2023-04-08 17:13:01 Functions: 100.0 % 89 89 85 4 89
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (60,120] days: 100.0 % 3 3 3
Legend: Lines: hit not hit (120,180] days: 54.0 % 50 27 23 27
(240..) days: 94.5 % 2349 2220 4 45 78 2 51 1335 93 741 97 1377
Function coverage date bins:
(60,120] days: 100.0 % 1 1 1
(120,180] days: 100.0 % 1 1 1
(240..) days: 50.3 % 173 87 85 2 86

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

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