LCOV - differential code coverage report
Current view: top level - src/backend/utils/adt - array_expanded.c (source / functions) Coverage Total Hit UBC GBC CBC
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 95.5 % 154 147 7 147
Current Date: 2024-04-14 14:21:10 Functions: 100.0 % 8 8 8
Baseline: 16@8cea358b128 Branches: 64.0 % 100 64 36 1 63
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed (240..) days: 95.5 % 154 147 7 147
Function coverage date bins:
(240..) days: 100.0 % 8 8 8
Branch coverage date bins:
(240..) days: 64.0 % 100 64 36 1 63

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * array_expanded.c
                                  4                 :                :  *    Basic functions for manipulating expanded arrays.
                                  5                 :                :  *
                                  6                 :                :  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
                                  7                 :                :  * Portions Copyright (c) 1994, Regents of the University of California
                                  8                 :                :  *
                                  9                 :                :  *
                                 10                 :                :  * IDENTIFICATION
                                 11                 :                :  *    src/backend/utils/adt/array_expanded.c
                                 12                 :                :  *
                                 13                 :                :  *-------------------------------------------------------------------------
                                 14                 :                :  */
                                 15                 :                : #include "postgres.h"
                                 16                 :                : 
                                 17                 :                : #include "access/tupmacs.h"
                                 18                 :                : #include "utils/array.h"
                                 19                 :                : #include "utils/lsyscache.h"
                                 20                 :                : #include "utils/memutils.h"
                                 21                 :                : 
                                 22                 :                : 
                                 23                 :                : /* "Methods" required for an expanded object */
                                 24                 :                : static Size EA_get_flat_size(ExpandedObjectHeader *eohptr);
                                 25                 :                : static void EA_flatten_into(ExpandedObjectHeader *eohptr,
                                 26                 :                :                             void *result, Size allocated_size);
                                 27                 :                : 
                                 28                 :                : static const ExpandedObjectMethods EA_methods =
                                 29                 :                : {
                                 30                 :                :     EA_get_flat_size,
                                 31                 :                :     EA_flatten_into
                                 32                 :                : };
                                 33                 :                : 
                                 34                 :                : /* Other local functions */
                                 35                 :                : static void copy_byval_expanded_array(ExpandedArrayHeader *eah,
                                 36                 :                :                                       ExpandedArrayHeader *oldeah);
                                 37                 :                : 
                                 38                 :                : 
                                 39                 :                : /*
                                 40                 :                :  * expand_array: convert an array Datum into an expanded array
                                 41                 :                :  *
                                 42                 :                :  * The expanded object will be a child of parentcontext.
                                 43                 :                :  *
                                 44                 :                :  * Some callers can provide cache space to avoid repeated lookups of element
                                 45                 :                :  * type data across calls; if so, pass a metacache pointer, making sure that
                                 46                 :                :  * metacache->element_type is initialized to InvalidOid before first call.
                                 47                 :                :  * If no cross-call caching is required, pass NULL for metacache.
                                 48                 :                :  */
                                 49                 :                : Datum
 3258 tgl@sss.pgh.pa.us          50                 :CBC        8285 : expand_array(Datum arraydatum, MemoryContext parentcontext,
                                 51                 :                :              ArrayMetaState *metacache)
                                 52                 :                : {
                                 53                 :                :     ArrayType  *array;
                                 54                 :                :     ExpandedArrayHeader *eah;
                                 55                 :                :     MemoryContext objcxt;
                                 56                 :                :     MemoryContext oldcxt;
                                 57                 :                :     ArrayMetaState fakecache;
                                 58                 :                : 
                                 59                 :                :     /*
                                 60                 :                :      * Allocate private context for expanded object.  We start by assuming
                                 61                 :                :      * that the array won't be very large; but if it does grow a lot, don't
                                 62                 :                :      * constrain aset.c's large-context behavior.
                                 63                 :                :      */
                                 64                 :           8285 :     objcxt = AllocSetContextCreate(parentcontext,
                                 65                 :                :                                    "expanded array",
                                 66                 :                :                                    ALLOCSET_START_SMALL_SIZES);
                                 67                 :                : 
                                 68                 :                :     /* Set up expanded array header */
                                 69                 :                :     eah = (ExpandedArrayHeader *)
                                 70                 :           8285 :         MemoryContextAlloc(objcxt, sizeof(ExpandedArrayHeader));
                                 71                 :                : 
                                 72                 :           8285 :     EOH_init_header(&eah->hdr, &EA_methods, objcxt);
                                 73                 :           8285 :     eah->ea_magic = EA_MAGIC;
                                 74                 :                : 
                                 75                 :                :     /* If the source is an expanded array, we may be able to optimize */
                                 76   [ +  +  +  + ]:           8285 :     if (VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(arraydatum)))
                                 77                 :                :     {
                                 78                 :             56 :         ExpandedArrayHeader *oldeah = (ExpandedArrayHeader *) DatumGetEOHP(arraydatum);
                                 79                 :                : 
                                 80         [ -  + ]:             56 :         Assert(oldeah->ea_magic == EA_MAGIC);
                                 81                 :                : 
                                 82                 :                :         /*
                                 83                 :                :          * Update caller's cache if provided; we don't need it this time, but
                                 84                 :                :          * next call might be for a non-expanded source array.  Furthermore,
                                 85                 :                :          * if the caller didn't provide a cache area, use some local storage
                                 86                 :                :          * to cache anyway, thereby avoiding a catalog lookup in the case
                                 87                 :                :          * where we fall through to the flat-copy code path.
                                 88                 :                :          */
                                 89         [ +  + ]:             56 :         if (metacache == NULL)
                                 90                 :             23 :             metacache = &fakecache;
                                 91                 :             56 :         metacache->element_type = oldeah->element_type;
                                 92                 :             56 :         metacache->typlen = oldeah->typlen;
                                 93                 :             56 :         metacache->typbyval = oldeah->typbyval;
                                 94                 :             56 :         metacache->typalign = oldeah->typalign;
                                 95                 :                : 
                                 96                 :                :         /*
                                 97                 :                :          * If element type is pass-by-value and we have a Datum-array
                                 98                 :                :          * representation, just copy the source's metadata and Datum/isnull
                                 99                 :                :          * arrays.  The original flat array, if present at all, adds no
                                100                 :                :          * additional information so we need not copy it.
                                101                 :                :          */
                                102   [ +  -  +  + ]:             56 :         if (oldeah->typbyval && oldeah->dvalues != NULL)
                                103                 :                :         {
                                104                 :             18 :             copy_byval_expanded_array(eah, oldeah);
                                105                 :                :             /* return a R/W pointer to the expanded array */
                                106                 :             18 :             return EOHPGetRWDatum(&eah->hdr);
                                107                 :                :         }
                                108                 :                : 
                                109                 :                :         /*
                                110                 :                :          * Otherwise, either we have only a flat representation or the
                                111                 :                :          * elements are pass-by-reference.  In either case, the best thing
                                112                 :                :          * seems to be to copy the source as a flat representation and then
                                113                 :                :          * deconstruct that later if necessary.  For the pass-by-ref case, we
                                114                 :                :          * could perhaps save some cycles with custom code that generates the
                                115                 :                :          * deconstructed representation in parallel with copying the values,
                                116                 :                :          * but it would be a lot of extra code for fairly marginal gain.  So,
                                117                 :                :          * fall through into the flat-source code path.
                                118                 :                :          */
                                119                 :                :     }
                                120                 :                : 
                                121                 :                :     /*
                                122                 :                :      * Detoast and copy source array into private context, as a flat array.
                                123                 :                :      *
                                124                 :                :      * Note that this coding risks leaking some memory in the private context
                                125                 :                :      * if we have to fetch data from a TOAST table; however, experimentation
                                126                 :                :      * says that the leak is minimal.  Doing it this way saves a copy step,
                                127                 :                :      * which seems worthwhile, especially if the array is large enough to need
                                128                 :                :      * external storage.
                                129                 :                :      */
                                130                 :           8267 :     oldcxt = MemoryContextSwitchTo(objcxt);
                                131                 :           8267 :     array = DatumGetArrayTypePCopy(arraydatum);
                                132                 :           8267 :     MemoryContextSwitchTo(oldcxt);
                                133                 :                : 
                                134                 :           8267 :     eah->ndims = ARR_NDIM(array);
                                135                 :                :     /* note these pointers point into the fvalue header! */
                                136                 :           8267 :     eah->dims = ARR_DIMS(array);
                                137                 :           8267 :     eah->lbound = ARR_LBOUND(array);
                                138                 :                : 
                                139                 :                :     /* Save array's element-type data for possible use later */
                                140                 :           8267 :     eah->element_type = ARR_ELEMTYPE(array);
                                141   [ +  +  +  + ]:           8267 :     if (metacache && metacache->element_type == eah->element_type)
                                142                 :                :     {
                                143                 :                :         /* We have a valid cache of representational data */
                                144                 :            329 :         eah->typlen = metacache->typlen;
                                145                 :            329 :         eah->typbyval = metacache->typbyval;
                                146                 :            329 :         eah->typalign = metacache->typalign;
                                147                 :                :     }
                                148                 :                :     else
                                149                 :                :     {
                                150                 :                :         /* No, so look it up */
                                151                 :           7938 :         get_typlenbyvalalign(eah->element_type,
                                152                 :                :                              &eah->typlen,
                                153                 :                :                              &eah->typbyval,
                                154                 :                :                              &eah->typalign);
                                155                 :                :         /* Update cache if provided */
                                156         [ +  + ]:           7938 :         if (metacache)
                                157                 :                :         {
                                158                 :            519 :             metacache->element_type = eah->element_type;
                                159                 :            519 :             metacache->typlen = eah->typlen;
                                160                 :            519 :             metacache->typbyval = eah->typbyval;
                                161                 :            519 :             metacache->typalign = eah->typalign;
                                162                 :                :         }
                                163                 :                :     }
                                164                 :                : 
                                165                 :                :     /* we don't make a deconstructed representation now */
                                166                 :           8267 :     eah->dvalues = NULL;
                                167                 :           8267 :     eah->dnulls = NULL;
                                168                 :           8267 :     eah->dvalueslen = 0;
                                169                 :           8267 :     eah->nelems = 0;
                                170                 :           8267 :     eah->flat_size = 0;
                                171                 :                : 
                                172                 :                :     /* remember we have a flat representation */
                                173                 :           8267 :     eah->fvalue = array;
                                174         [ +  + ]:           8267 :     eah->fstartptr = ARR_DATA_PTR(array);
                                175                 :           8267 :     eah->fendptr = ((char *) array) + ARR_SIZE(array);
                                176                 :                : 
                                177                 :                :     /* return a R/W pointer to the expanded array */
                                178                 :           8267 :     return EOHPGetRWDatum(&eah->hdr);
                                179                 :                : }
                                180                 :                : 
                                181                 :                : /*
                                182                 :                :  * helper for expand_array(): copy pass-by-value Datum-array representation
                                183                 :                :  */
                                184                 :                : static void
                                185                 :             18 : copy_byval_expanded_array(ExpandedArrayHeader *eah,
                                186                 :                :                           ExpandedArrayHeader *oldeah)
                                187                 :                : {
                                188                 :             18 :     MemoryContext objcxt = eah->hdr.eoh_context;
                                189                 :             18 :     int         ndims = oldeah->ndims;
                                190                 :             18 :     int         dvalueslen = oldeah->dvalueslen;
                                191                 :                : 
                                192                 :                :     /* Copy array dimensionality information */
                                193                 :             18 :     eah->ndims = ndims;
                                194                 :                :     /* We can alloc both dimensionality arrays with one palloc */
                                195                 :             18 :     eah->dims = (int *) MemoryContextAlloc(objcxt, ndims * 2 * sizeof(int));
                                196                 :             18 :     eah->lbound = eah->dims + ndims;
                                197                 :                :     /* .. but don't assume the source's arrays are contiguous */
                                198                 :             18 :     memcpy(eah->dims, oldeah->dims, ndims * sizeof(int));
                                199                 :             18 :     memcpy(eah->lbound, oldeah->lbound, ndims * sizeof(int));
                                200                 :                : 
                                201                 :                :     /* Copy element-type data */
                                202                 :             18 :     eah->element_type = oldeah->element_type;
                                203                 :             18 :     eah->typlen = oldeah->typlen;
                                204                 :             18 :     eah->typbyval = oldeah->typbyval;
                                205                 :             18 :     eah->typalign = oldeah->typalign;
                                206                 :                : 
                                207                 :                :     /* Copy the deconstructed representation */
                                208                 :             18 :     eah->dvalues = (Datum *) MemoryContextAlloc(objcxt,
                                209                 :                :                                                 dvalueslen * sizeof(Datum));
                                210                 :             18 :     memcpy(eah->dvalues, oldeah->dvalues, dvalueslen * sizeof(Datum));
                                211         [ -  + ]:             18 :     if (oldeah->dnulls)
                                212                 :                :     {
 3258 tgl@sss.pgh.pa.us         213                 :UBC           0 :         eah->dnulls = (bool *) MemoryContextAlloc(objcxt,
                                214                 :                :                                                   dvalueslen * sizeof(bool));
                                215                 :              0 :         memcpy(eah->dnulls, oldeah->dnulls, dvalueslen * sizeof(bool));
                                216                 :                :     }
                                217                 :                :     else
 3258 tgl@sss.pgh.pa.us         218                 :CBC          18 :         eah->dnulls = NULL;
                                219                 :             18 :     eah->dvalueslen = dvalueslen;
                                220                 :             18 :     eah->nelems = oldeah->nelems;
                                221                 :             18 :     eah->flat_size = oldeah->flat_size;
                                222                 :                : 
                                223                 :                :     /* we don't make a flat representation */
                                224                 :             18 :     eah->fvalue = NULL;
                                225                 :             18 :     eah->fstartptr = NULL;
                                226                 :             18 :     eah->fendptr = NULL;
                                227                 :             18 : }
                                228                 :                : 
                                229                 :                : /*
                                230                 :                :  * get_flat_size method for expanded arrays
                                231                 :                :  */
                                232                 :                : static Size
                                233                 :           6058 : EA_get_flat_size(ExpandedObjectHeader *eohptr)
                                234                 :                : {
                                235                 :           6058 :     ExpandedArrayHeader *eah = (ExpandedArrayHeader *) eohptr;
                                236                 :                :     int         nelems;
                                237                 :                :     int         ndims;
                                238                 :                :     Datum      *dvalues;
                                239                 :                :     bool       *dnulls;
                                240                 :                :     Size        nbytes;
                                241                 :                :     int         i;
                                242                 :                : 
                                243         [ -  + ]:           6058 :     Assert(eah->ea_magic == EA_MAGIC);
                                244                 :                : 
                                245                 :                :     /* Easy if we have a valid flattened value */
                                246         [ +  + ]:           6058 :     if (eah->fvalue)
                                247                 :           3049 :         return ARR_SIZE(eah->fvalue);
                                248                 :                : 
                                249                 :                :     /* If we have a cached size value, believe that */
                                250         [ +  + ]:           3009 :     if (eah->flat_size)
                                251                 :           2128 :         return eah->flat_size;
                                252                 :                : 
                                253                 :                :     /*
                                254                 :                :      * Compute space needed by examining dvalues/dnulls.  Note that the result
                                255                 :                :      * array will have a nulls bitmap if dnulls isn't NULL, even if the array
                                256                 :                :      * doesn't actually contain any nulls now.
                                257                 :                :      */
                                258                 :            881 :     nelems = eah->nelems;
                                259                 :            881 :     ndims = eah->ndims;
                                260         [ -  + ]:            881 :     Assert(nelems == ArrayGetNItems(ndims, eah->dims));
                                261                 :            881 :     dvalues = eah->dvalues;
                                262                 :            881 :     dnulls = eah->dnulls;
                                263                 :            881 :     nbytes = 0;
                                264         [ +  + ]:           3212 :     for (i = 0; i < nelems; i++)
                                265                 :                :     {
                                266   [ -  +  -  - ]:           2331 :         if (dnulls && dnulls[i])
 3258 tgl@sss.pgh.pa.us         267                 :UBC           0 :             continue;
 3258 tgl@sss.pgh.pa.us         268   [ +  +  +  -  :CBC        2331 :         nbytes = att_addlength_datum(nbytes, eah->typlen, dvalues[i]);
                                     -  +  -  -  -  
                                     -  -  -  -  +  
                                              -  - ]
                                269   [ +  +  +  -  :           2331 :         nbytes = att_align_nominal(nbytes, eah->typalign);
                                        +  -  -  - ]
                                270                 :                :         /* check for overflow of total request */
                                271         [ -  + ]:           2331 :         if (!AllocSizeIsValid(nbytes))
 3258 tgl@sss.pgh.pa.us         272         [ #  # ]:UBC           0 :             ereport(ERROR,
                                273                 :                :                     (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                                274                 :                :                      errmsg("array size exceeds the maximum allowed (%d)",
                                275                 :                :                             (int) MaxAllocSize)));
                                276                 :                :     }
                                277                 :                : 
 3258 tgl@sss.pgh.pa.us         278         [ -  + ]:CBC         881 :     if (dnulls)
 3258 tgl@sss.pgh.pa.us         279                 :UBC           0 :         nbytes += ARR_OVERHEAD_WITHNULLS(ndims, nelems);
                                280                 :                :     else
 3258 tgl@sss.pgh.pa.us         281                 :CBC         881 :         nbytes += ARR_OVERHEAD_NONULLS(ndims);
                                282                 :                : 
                                283                 :                :     /* cache for next time */
                                284                 :            881 :     eah->flat_size = nbytes;
                                285                 :                : 
                                286                 :            881 :     return nbytes;
                                287                 :                : }
                                288                 :                : 
                                289                 :                : /*
                                290                 :                :  * flatten_into method for expanded arrays
                                291                 :                :  */
                                292                 :                : static void
                                293                 :           4575 : EA_flatten_into(ExpandedObjectHeader *eohptr,
                                294                 :                :                 void *result, Size allocated_size)
                                295                 :                : {
                                296                 :           4575 :     ExpandedArrayHeader *eah = (ExpandedArrayHeader *) eohptr;
                                297                 :           4575 :     ArrayType  *aresult = (ArrayType *) result;
                                298                 :                :     int         nelems;
                                299                 :                :     int         ndims;
                                300                 :                :     int32       dataoffset;
                                301                 :                : 
                                302         [ -  + ]:           4575 :     Assert(eah->ea_magic == EA_MAGIC);
                                303                 :                : 
                                304                 :                :     /* Easy if we have a valid flattened value */
                                305         [ +  + ]:           4575 :     if (eah->fvalue)
                                306                 :                :     {
                                307         [ -  + ]:           3022 :         Assert(allocated_size == ARR_SIZE(eah->fvalue));
                                308                 :           3022 :         memcpy(result, eah->fvalue, allocated_size);
                                309                 :           3022 :         return;
                                310                 :                :     }
                                311                 :                : 
                                312                 :                :     /* Else allocation should match previous get_flat_size result */
                                313         [ -  + ]:           1553 :     Assert(allocated_size == eah->flat_size);
                                314                 :                : 
                                315                 :                :     /* Fill result array from dvalues/dnulls */
                                316                 :           1553 :     nelems = eah->nelems;
                                317                 :           1553 :     ndims = eah->ndims;
                                318                 :                : 
                                319         [ -  + ]:           1553 :     if (eah->dnulls)
 3258 tgl@sss.pgh.pa.us         320                 :UBC           0 :         dataoffset = ARR_OVERHEAD_WITHNULLS(ndims, nelems);
                                321                 :                :     else
 3258 tgl@sss.pgh.pa.us         322                 :CBC        1553 :         dataoffset = 0;         /* marker for no null bitmap */
                                323                 :                : 
                                324                 :                :     /* We must ensure that any pad space is zero-filled */
                                325                 :           1553 :     memset(aresult, 0, allocated_size);
                                326                 :                : 
                                327                 :           1553 :     SET_VARSIZE(aresult, allocated_size);
                                328                 :           1553 :     aresult->ndim = ndims;
                                329                 :           1553 :     aresult->dataoffset = dataoffset;
                                330                 :           1553 :     aresult->elemtype = eah->element_type;
                                331                 :           1553 :     memcpy(ARR_DIMS(aresult), eah->dims, ndims * sizeof(int));
                                332                 :           1553 :     memcpy(ARR_LBOUND(aresult), eah->lbound, ndims * sizeof(int));
                                333                 :                : 
                                334                 :           1553 :     CopyArrayEls(aresult,
                                335                 :                :                  eah->dvalues, eah->dnulls, nelems,
                                336                 :           1553 :                  eah->typlen, eah->typbyval, eah->typalign,
                                337                 :                :                  false);
                                338                 :                : }
                                339                 :                : 
                                340                 :                : /*
                                341                 :                :  * Argument fetching support code
                                342                 :                :  */
                                343                 :                : 
                                344                 :                : /*
                                345                 :                :  * DatumGetExpandedArray: get a writable expanded array from an input argument
                                346                 :                :  *
                                347                 :                :  * Caution: if the input is a read/write pointer, this returns the input
                                348                 :                :  * argument; so callers must be sure that their changes are "safe", that is
                                349                 :                :  * they cannot leave the array in a corrupt state.
                                350                 :                :  */
                                351                 :                : ExpandedArrayHeader *
                                352                 :           1827 : DatumGetExpandedArray(Datum d)
                                353                 :                : {
                                354                 :                :     /* If it's a writable expanded array already, just return it */
                                355   [ +  +  +  + ]:           1827 :     if (VARATT_IS_EXTERNAL_EXPANDED_RW(DatumGetPointer(d)))
                                356                 :                :     {
                                357                 :            982 :         ExpandedArrayHeader *eah = (ExpandedArrayHeader *) DatumGetEOHP(d);
                                358                 :                : 
                                359         [ -  + ]:            982 :         Assert(eah->ea_magic == EA_MAGIC);
                                360                 :            982 :         return eah;
                                361                 :                :     }
                                362                 :                : 
                                363                 :                :     /* Else expand the hard way */
                                364                 :            845 :     d = expand_array(d, CurrentMemoryContext, NULL);
                                365                 :            845 :     return (ExpandedArrayHeader *) DatumGetEOHP(d);
                                366                 :                : }
                                367                 :                : 
                                368                 :                : /*
                                369                 :                :  * As above, when caller has the ability to cache element type info
                                370                 :                :  */
                                371                 :                : ExpandedArrayHeader *
                                372                 :            958 : DatumGetExpandedArrayX(Datum d, ArrayMetaState *metacache)
                                373                 :                : {
                                374                 :                :     /* If it's a writable expanded array already, just return it */
                                375   [ +  +  +  + ]:            958 :     if (VARATT_IS_EXTERNAL_EXPANDED_RW(DatumGetPointer(d)))
                                376                 :                :     {
                                377                 :            127 :         ExpandedArrayHeader *eah = (ExpandedArrayHeader *) DatumGetEOHP(d);
                                378                 :                : 
                                379         [ -  + ]:            127 :         Assert(eah->ea_magic == EA_MAGIC);
                                380                 :                :         /* Update cache if provided */
                                381         [ +  - ]:            127 :         if (metacache)
                                382                 :                :         {
                                383                 :            127 :             metacache->element_type = eah->element_type;
                                384                 :            127 :             metacache->typlen = eah->typlen;
                                385                 :            127 :             metacache->typbyval = eah->typbyval;
                                386                 :            127 :             metacache->typalign = eah->typalign;
                                387                 :                :         }
                                388                 :            127 :         return eah;
                                389                 :                :     }
                                390                 :                : 
                                391                 :                :     /* Else expand using caller's cache if any */
                                392                 :            831 :     d = expand_array(d, CurrentMemoryContext, metacache);
                                393                 :            831 :     return (ExpandedArrayHeader *) DatumGetEOHP(d);
                                394                 :                : }
                                395                 :                : 
                                396                 :                : /*
                                397                 :                :  * DatumGetAnyArrayP: return either an expanded array or a detoasted varlena
                                398                 :                :  * array.  The result must not be modified in-place.
                                399                 :                :  */
                                400                 :                : AnyArrayType *
 2400                           401                 :        8708235 : DatumGetAnyArrayP(Datum d)
                                402                 :                : {
                                403                 :                :     ExpandedArrayHeader *eah;
                                404                 :                : 
                                405                 :                :     /*
                                406                 :                :      * If it's an expanded array (RW or RO), return the header pointer.
                                407                 :                :      */
 3258                           408   [ +  +  +  + ]:        8708235 :     if (VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(d)))
                                409                 :                :     {
                                410                 :           9123 :         eah = (ExpandedArrayHeader *) DatumGetEOHP(d);
                                411         [ -  + ]:           9123 :         Assert(eah->ea_magic == EA_MAGIC);
                                412                 :           9123 :         return (AnyArrayType *) eah;
                                413                 :                :     }
                                414                 :                : 
                                415                 :                :     /* Else do regular detoasting as needed */
                                416                 :        8699112 :     return (AnyArrayType *) PG_DETOAST_DATUM(d);
                                417                 :                : }
                                418                 :                : 
                                419                 :                : /*
                                420                 :                :  * Create the Datum/isnull representation of an expanded array object
                                421                 :                :  * if we didn't do so previously
                                422                 :                :  */
                                423                 :                : void
                                424                 :           6882 : deconstruct_expanded_array(ExpandedArrayHeader *eah)
                                425                 :                : {
                                426         [ +  + ]:           6882 :     if (eah->dvalues == NULL)
                                427                 :                :     {
                                428                 :           5500 :         MemoryContext oldcxt = MemoryContextSwitchTo(eah->hdr.eoh_context);
                                429                 :                :         Datum      *dvalues;
                                430                 :                :         bool       *dnulls;
                                431                 :                :         int         nelems;
                                432                 :                : 
                                433                 :           5500 :         dnulls = NULL;
 3258 tgl@sss.pgh.pa.us         434                 :UBC           0 :         deconstruct_array(eah->fvalue,
                                435                 :                :                           eah->element_type,
 3258 tgl@sss.pgh.pa.us         436                 :CBC        5500 :                           eah->typlen, eah->typbyval, eah->typalign,
                                437                 :                :                           &dvalues,
                                438         [ -  + ]:           5500 :                           ARR_HASNULL(eah->fvalue) ? &dnulls : NULL,
                                439                 :                :                           &nelems);
                                440                 :                : 
                                441                 :                :         /*
                                442                 :                :          * Update header only after successful completion of this step.  If
                                443                 :                :          * deconstruct_array fails partway through, worst consequence is some
                                444                 :                :          * leaked memory in the object's context.  If the caller fails at a
                                445                 :                :          * later point, that's fine, since the deconstructed representation is
                                446                 :                :          * valid anyhow.
                                447                 :                :          */
                                448                 :           5500 :         eah->dvalues = dvalues;
                                449                 :           5500 :         eah->dnulls = dnulls;
                                450                 :           5500 :         eah->dvalueslen = eah->nelems = nelems;
                                451                 :           5500 :         MemoryContextSwitchTo(oldcxt);
                                452                 :                :     }
                                453                 :           6882 : }
        

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