LCOV - code coverage report
Current view: top level - src/backend/utils/adt - array_expanded.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 95.9 % 195 187
Test Date: 2026-01-26 10:56:24 Functions: 100.0 % 8 8
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 63.6 % 88 56

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * array_expanded.c
       4                 :             :  *        Basic functions for manipulating expanded arrays.
       5                 :             :  *
       6                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
       8                 :             :  *
       9                 :             :  *
      10                 :             :  * IDENTIFICATION
      11                 :             :  *        src/backend/utils/adt/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
      50                 :        2189 : expand_array(Datum arraydatum, MemoryContext parentcontext,
      51                 :             :                          ArrayMetaState *metacache)
      52                 :             : {
      53                 :        2189 :         ArrayType  *array;
      54                 :        2189 :         ExpandedArrayHeader *eah;
      55                 :        2189 :         MemoryContext objcxt;
      56                 :        2189 :         MemoryContext oldcxt;
      57                 :        2189 :         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                 :        2189 :         objcxt = AllocSetContextCreate(parentcontext,
      65                 :             :                                                                    "expanded array",
      66                 :             :                                                                    ALLOCSET_START_SMALL_SIZES);
      67                 :             : 
      68                 :             :         /* Set up expanded array header */
      69                 :        2189 :         eah = (ExpandedArrayHeader *)
      70                 :        2189 :                 MemoryContextAlloc(objcxt, sizeof(ExpandedArrayHeader));
      71                 :             : 
      72                 :        2189 :         EOH_init_header(&eah->hdr, &EA_methods, objcxt);
      73                 :        2189 :         eah->ea_magic = EA_MAGIC;
      74                 :             : 
      75                 :             :         /* If the source is an expanded array, we may be able to optimize */
      76         [ +  + ]:        2189 :         if (VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(arraydatum)))
      77                 :             :         {
      78                 :           7 :                 ExpandedArrayHeader *oldeah = (ExpandedArrayHeader *) DatumGetEOHP(arraydatum);
      79                 :             : 
      80         [ +  - ]:           7 :                 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         [ +  + ]:           7 :                 if (metacache == NULL)
      90                 :           2 :                         metacache = &fakecache;
      91                 :           7 :                 metacache->element_type = oldeah->element_type;
      92                 :           7 :                 metacache->typlen = oldeah->typlen;
      93                 :           7 :                 metacache->typbyval = oldeah->typbyval;
      94                 :           7 :                 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   [ +  -  +  + ]:           7 :                 if (oldeah->typbyval && oldeah->dvalues != NULL)
     103                 :             :                 {
     104                 :           2 :                         copy_byval_expanded_array(eah, oldeah);
     105                 :             :                         /* return a R/W pointer to the expanded array */
     106                 :           2 :                         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         [ +  + ]:           7 :         }
     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                 :        2187 :         oldcxt = MemoryContextSwitchTo(objcxt);
     131                 :        2187 :         array = DatumGetArrayTypePCopy(arraydatum);
     132                 :        2187 :         MemoryContextSwitchTo(oldcxt);
     133                 :             : 
     134                 :        2187 :         eah->ndims = ARR_NDIM(array);
     135                 :             :         /* note these pointers point into the fvalue header! */
     136                 :        2187 :         eah->dims = ARR_DIMS(array);
     137                 :        2187 :         eah->lbound = ARR_LBOUND(array);
     138                 :             : 
     139                 :             :         /* Save array's element-type data for possible use later */
     140                 :        2187 :         eah->element_type = ARR_ELEMTYPE(array);
     141   [ +  +  +  + ]:        2187 :         if (metacache && metacache->element_type == eah->element_type)
     142                 :             :         {
     143                 :             :                 /* We have a valid cache of representational data */
     144                 :         102 :                 eah->typlen = metacache->typlen;
     145                 :         102 :                 eah->typbyval = metacache->typbyval;
     146                 :         102 :                 eah->typalign = metacache->typalign;
     147                 :         102 :         }
     148                 :             :         else
     149                 :             :         {
     150                 :             :                 /* No, so look it up */
     151                 :        4170 :                 get_typlenbyvalalign(eah->element_type,
     152                 :        2085 :                                                          &eah->typlen,
     153                 :        2085 :                                                          &eah->typbyval,
     154                 :        2085 :                                                          &eah->typalign);
     155                 :             :                 /* Update cache if provided */
     156         [ +  + ]:        2085 :                 if (metacache)
     157                 :             :                 {
     158                 :         177 :                         metacache->element_type = eah->element_type;
     159                 :         177 :                         metacache->typlen = eah->typlen;
     160                 :         177 :                         metacache->typbyval = eah->typbyval;
     161                 :         177 :                         metacache->typalign = eah->typalign;
     162                 :         177 :                 }
     163                 :             :         }
     164                 :             : 
     165                 :             :         /* we don't make a deconstructed representation now */
     166                 :        2187 :         eah->dvalues = NULL;
     167                 :        2187 :         eah->dnulls = NULL;
     168                 :        2187 :         eah->dvalueslen = 0;
     169                 :        2187 :         eah->nelems = 0;
     170                 :        2187 :         eah->flat_size = 0;
     171                 :             : 
     172                 :             :         /* remember we have a flat representation */
     173                 :        2187 :         eah->fvalue = array;
     174         [ -  + ]:        2187 :         eah->fstartptr = ARR_DATA_PTR(array);
     175                 :        2187 :         eah->fendptr = ((char *) array) + ARR_SIZE(array);
     176                 :             : 
     177                 :             :         /* return a R/W pointer to the expanded array */
     178                 :        2187 :         return EOHPGetRWDatum(&eah->hdr);
     179                 :        2189 : }
     180                 :             : 
     181                 :             : /*
     182                 :             :  * helper for expand_array(): copy pass-by-value Datum-array representation
     183                 :             :  */
     184                 :             : static void
     185                 :           2 : copy_byval_expanded_array(ExpandedArrayHeader *eah,
     186                 :             :                                                   ExpandedArrayHeader *oldeah)
     187                 :             : {
     188                 :           2 :         MemoryContext objcxt = eah->hdr.eoh_context;
     189                 :           2 :         int                     ndims = oldeah->ndims;
     190                 :           2 :         int                     dvalueslen = oldeah->dvalueslen;
     191                 :             : 
     192                 :             :         /* Copy array dimensionality information */
     193                 :           2 :         eah->ndims = ndims;
     194                 :             :         /* We can alloc both dimensionality arrays with one palloc */
     195                 :           2 :         eah->dims = (int *) MemoryContextAlloc(objcxt, ndims * 2 * sizeof(int));
     196                 :           2 :         eah->lbound = eah->dims + ndims;
     197                 :             :         /* .. but don't assume the source's arrays are contiguous */
     198                 :           2 :         memcpy(eah->dims, oldeah->dims, ndims * sizeof(int));
     199                 :           2 :         memcpy(eah->lbound, oldeah->lbound, ndims * sizeof(int));
     200                 :             : 
     201                 :             :         /* Copy element-type data */
     202                 :           2 :         eah->element_type = oldeah->element_type;
     203                 :           2 :         eah->typlen = oldeah->typlen;
     204                 :           2 :         eah->typbyval = oldeah->typbyval;
     205                 :           2 :         eah->typalign = oldeah->typalign;
     206                 :             : 
     207                 :             :         /* Copy the deconstructed representation */
     208                 :           4 :         eah->dvalues = (Datum *) MemoryContextAlloc(objcxt,
     209                 :           2 :                                                                                                 dvalueslen * sizeof(Datum));
     210                 :           2 :         memcpy(eah->dvalues, oldeah->dvalues, dvalueslen * sizeof(Datum));
     211         [ -  + ]:           2 :         if (oldeah->dnulls)
     212                 :             :         {
     213                 :           0 :                 eah->dnulls = (bool *) MemoryContextAlloc(objcxt,
     214                 :           0 :                                                                                                   dvalueslen * sizeof(bool));
     215                 :           0 :                 memcpy(eah->dnulls, oldeah->dnulls, dvalueslen * sizeof(bool));
     216                 :           0 :         }
     217                 :             :         else
     218                 :           2 :                 eah->dnulls = NULL;
     219                 :           2 :         eah->dvalueslen = dvalueslen;
     220                 :           2 :         eah->nelems = oldeah->nelems;
     221                 :           2 :         eah->flat_size = oldeah->flat_size;
     222                 :             : 
     223                 :             :         /* we don't make a flat representation */
     224                 :           2 :         eah->fvalue = NULL;
     225                 :           2 :         eah->fstartptr = NULL;
     226                 :           2 :         eah->fendptr = NULL;
     227                 :           2 : }
     228                 :             : 
     229                 :             : /*
     230                 :             :  * get_flat_size method for expanded arrays
     231                 :             :  */
     232                 :             : static Size
     233                 :        1427 : EA_get_flat_size(ExpandedObjectHeader *eohptr)
     234                 :             : {
     235                 :        1427 :         ExpandedArrayHeader *eah = (ExpandedArrayHeader *) eohptr;
     236                 :        1427 :         int                     nelems;
     237                 :        1427 :         int                     ndims;
     238                 :        1427 :         Datum      *dvalues;
     239                 :        1427 :         bool       *dnulls;
     240                 :        1427 :         Size            nbytes;
     241                 :        1427 :         int                     i;
     242                 :             : 
     243         [ +  - ]:        1427 :         Assert(eah->ea_magic == EA_MAGIC);
     244                 :             : 
     245                 :             :         /* Easy if we have a valid flattened value */
     246         [ +  + ]:        1427 :         if (eah->fvalue)
     247                 :         463 :                 return ARR_SIZE(eah->fvalue);
     248                 :             : 
     249                 :             :         /* If we have a cached size value, believe that */
     250         [ +  + ]:         964 :         if (eah->flat_size)
     251                 :         681 :                 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                 :         283 :         nelems = eah->nelems;
     259                 :         283 :         ndims = eah->ndims;
     260         [ +  - ]:         283 :         Assert(nelems == ArrayGetNItems(ndims, eah->dims));
     261                 :         283 :         dvalues = eah->dvalues;
     262                 :         283 :         dnulls = eah->dnulls;
     263                 :         283 :         nbytes = 0;
     264         [ +  + ]:        1060 :         for (i = 0; i < nelems; i++)
     265                 :             :         {
     266   [ -  +  #  # ]:         777 :                 if (dnulls && dnulls[i])
     267                 :           0 :                         continue;
     268   [ +  +  -  +  :         777 :                 nbytes = att_addlength_datum(nbytes, eah->typlen, dvalues[i]);
                   #  # ]
     269   [ +  +  -  +  :         777 :                 nbytes = att_align_nominal(nbytes, eah->typalign);
             +  -  #  # ]
     270                 :             :                 /* check for overflow of total request */
     271         [ +  - ]:         777 :                 if (!AllocSizeIsValid(nbytes))
     272   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     273                 :             :                                         (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     274                 :             :                                          errmsg("array size exceeds the maximum allowed (%zu)",
     275                 :             :                                                         MaxAllocSize)));
     276                 :         777 :         }
     277                 :             : 
     278         [ -  + ]:         283 :         if (dnulls)
     279                 :           0 :                 nbytes += ARR_OVERHEAD_WITHNULLS(ndims, nelems);
     280                 :             :         else
     281                 :         283 :                 nbytes += ARR_OVERHEAD_NONULLS(ndims);
     282                 :             : 
     283                 :             :         /* cache for next time */
     284                 :         283 :         eah->flat_size = nbytes;
     285                 :             : 
     286                 :         283 :         return nbytes;
     287                 :        1427 : }
     288                 :             : 
     289                 :             : /*
     290                 :             :  * flatten_into method for expanded arrays
     291                 :             :  */
     292                 :             : static void
     293                 :         964 : EA_flatten_into(ExpandedObjectHeader *eohptr,
     294                 :             :                                 void *result, Size allocated_size)
     295                 :             : {
     296                 :         964 :         ExpandedArrayHeader *eah = (ExpandedArrayHeader *) eohptr;
     297                 :         964 :         ArrayType  *aresult = (ArrayType *) result;
     298                 :         964 :         int                     nelems;
     299                 :         964 :         int                     ndims;
     300                 :         964 :         int32           dataoffset;
     301                 :             : 
     302         [ +  - ]:         964 :         Assert(eah->ea_magic == EA_MAGIC);
     303                 :             : 
     304                 :             :         /* Easy if we have a valid flattened value */
     305         [ +  + ]:         964 :         if (eah->fvalue)
     306                 :             :         {
     307         [ +  - ]:         455 :                 Assert(allocated_size == ARR_SIZE(eah->fvalue));
     308                 :         455 :                 memcpy(result, eah->fvalue, allocated_size);
     309                 :         455 :                 return;
     310                 :             :         }
     311                 :             : 
     312                 :             :         /* Else allocation should match previous get_flat_size result */
     313         [ +  - ]:         509 :         Assert(allocated_size == eah->flat_size);
     314                 :             : 
     315                 :             :         /* Fill result array from dvalues/dnulls */
     316                 :         509 :         nelems = eah->nelems;
     317                 :         509 :         ndims = eah->ndims;
     318                 :             : 
     319         [ -  + ]:         509 :         if (eah->dnulls)
     320                 :           0 :                 dataoffset = ARR_OVERHEAD_WITHNULLS(ndims, nelems);
     321                 :             :         else
     322                 :         509 :                 dataoffset = 0;                 /* marker for no null bitmap */
     323                 :             : 
     324                 :             :         /* We must ensure that any pad space is zero-filled */
     325                 :         509 :         memset(aresult, 0, allocated_size);
     326                 :             : 
     327                 :         509 :         SET_VARSIZE(aresult, allocated_size);
     328                 :         509 :         aresult->ndim = ndims;
     329                 :         509 :         aresult->dataoffset = dataoffset;
     330                 :         509 :         aresult->elemtype = eah->element_type;
     331                 :         509 :         memcpy(ARR_DIMS(aresult), eah->dims, ndims * sizeof(int));
     332                 :         509 :         memcpy(ARR_LBOUND(aresult), eah->lbound, ndims * sizeof(int));
     333                 :             : 
     334                 :        1018 :         CopyArrayEls(aresult,
     335                 :         509 :                                  eah->dvalues, eah->dnulls, nelems,
     336                 :         509 :                                  eah->typlen, eah->typbyval, eah->typalign,
     337                 :             :                                  false);
     338         [ -  + ]:         964 : }
     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                 :         585 : DatumGetExpandedArray(Datum d)
     353                 :             : {
     354                 :             :         /* If it's a writable expanded array already, just return it */
     355         [ +  + ]:         585 :         if (VARATT_IS_EXTERNAL_EXPANDED_RW(DatumGetPointer(d)))
     356                 :             :         {
     357                 :         308 :                 ExpandedArrayHeader *eah = (ExpandedArrayHeader *) DatumGetEOHP(d);
     358                 :             : 
     359         [ +  - ]:         308 :                 Assert(eah->ea_magic == EA_MAGIC);
     360                 :         308 :                 return eah;
     361                 :         308 :         }
     362                 :             : 
     363                 :             :         /* Else expand the hard way */
     364                 :         277 :         d = expand_array(d, CurrentMemoryContext, NULL);
     365                 :         277 :         return (ExpandedArrayHeader *) DatumGetEOHP(d);
     366                 :         585 : }
     367                 :             : 
     368                 :             : /*
     369                 :             :  * As above, when caller has the ability to cache element type info
     370                 :             :  */
     371                 :             : ExpandedArrayHeader *
     372                 :         296 : DatumGetExpandedArrayX(Datum d, ArrayMetaState *metacache)
     373                 :             : {
     374                 :             :         /* If it's a writable expanded array already, just return it */
     375         [ +  + ]:         296 :         if (VARATT_IS_EXTERNAL_EXPANDED_RW(DatumGetPointer(d)))
     376                 :             :         {
     377                 :          21 :                 ExpandedArrayHeader *eah = (ExpandedArrayHeader *) DatumGetEOHP(d);
     378                 :             : 
     379         [ +  - ]:          21 :                 Assert(eah->ea_magic == EA_MAGIC);
     380                 :             :                 /* Update cache if provided */
     381         [ -  + ]:          21 :                 if (metacache)
     382                 :             :                 {
     383                 :          21 :                         metacache->element_type = eah->element_type;
     384                 :          21 :                         metacache->typlen = eah->typlen;
     385                 :          21 :                         metacache->typbyval = eah->typbyval;
     386                 :          21 :                         metacache->typalign = eah->typalign;
     387                 :          21 :                 }
     388                 :          21 :                 return eah;
     389                 :          21 :         }
     390                 :             : 
     391                 :             :         /* Else expand using caller's cache if any */
     392                 :         275 :         d = expand_array(d, CurrentMemoryContext, metacache);
     393                 :         275 :         return (ExpandedArrayHeader *) DatumGetEOHP(d);
     394                 :         296 : }
     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 *
     401                 :     2384986 : DatumGetAnyArrayP(Datum d)
     402                 :             : {
     403                 :     2384986 :         ExpandedArrayHeader *eah;
     404                 :             : 
     405                 :             :         /*
     406                 :             :          * If it's an expanded array (RW or RO), return the header pointer.
     407                 :             :          */
     408         [ +  + ]:     2384986 :         if (VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(d)))
     409                 :             :         {
     410                 :        3036 :                 eah = (ExpandedArrayHeader *) DatumGetEOHP(d);
     411         [ +  - ]:        3036 :                 Assert(eah->ea_magic == EA_MAGIC);
     412                 :        3036 :                 return (AnyArrayType *) eah;
     413                 :             :         }
     414                 :             : 
     415                 :             :         /* Else do regular detoasting as needed */
     416                 :     2381950 :         return (AnyArrayType *) PG_DETOAST_DATUM(d);
     417                 :     2384986 : }
     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                 :        2265 : deconstruct_expanded_array(ExpandedArrayHeader *eah)
     425                 :             : {
     426         [ +  + ]:        2265 :         if (eah->dvalues == NULL)
     427                 :             :         {
     428                 :        1820 :                 MemoryContext oldcxt = MemoryContextSwitchTo(eah->hdr.eoh_context);
     429                 :        1820 :                 Datum      *dvalues;
     430                 :        1820 :                 bool       *dnulls;
     431                 :        1820 :                 int                     nelems;
     432                 :             : 
     433                 :        1820 :                 dnulls = NULL;
     434                 :        3640 :                 deconstruct_array(eah->fvalue,
     435                 :        1820 :                                                   eah->element_type,
     436                 :        1820 :                                                   eah->typlen, eah->typbyval, eah->typalign,
     437                 :             :                                                   &dvalues,
     438         [ -  + ]:        1820 :                                                   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                 :        1820 :                 eah->dvalues = dvalues;
     449                 :        1820 :                 eah->dnulls = dnulls;
     450                 :        1820 :                 eah->dvalueslen = eah->nelems = nelems;
     451                 :        1820 :                 MemoryContextSwitchTo(oldcxt);
     452                 :        1820 :         }
     453                 :        2265 : }
        

Generated by: LCOV version 2.3.2-1