Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  array_expanded.c   Sprache: unbekannt

 
/*-------------------------------------------------------------------------
 *
 * array_expanded.c
 *   Basic functions for manipulating expanded arrays.
 *
 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *   src/backend/utils/adt/array_expanded.c
 *
 *-------------------------------------------------------------------------
 */

#include "postgres.h"

#include "access/tupmacs.h"
#include "utils/array.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"


/* "Methods" required for an expanded object */
static Size EA_get_flat_size(ExpandedObjectHeader *eohptr);
static void EA_flatten_into(ExpandedObjectHeader *eohptr,
       void *result, Size allocated_size);

static const ExpandedObjectMethods EA_methods =
{
 EA_get_flat_size,
 EA_flatten_into
};

/* Other local functions */
static void copy_byval_expanded_array(ExpandedArrayHeader *eah,
           ExpandedArrayHeader *oldeah);


/*
 * expand_array: convert an array Datum into an expanded array
 *
 * The expanded object will be a child of parentcontext.
 *
 * Some callers can provide cache space to avoid repeated lookups of element
 * type data across calls; if so, pass a metacache pointer, making sure that
 * metacache->element_type is initialized to InvalidOid before first call.
 * If no cross-call caching is required, pass NULL for metacache.
 */

Datum
expand_array(Datum arraydatum, MemoryContext parentcontext,
    ArrayMetaState *metacache)
{
 ArrayType  *array;
 ExpandedArrayHeader *eah;
 MemoryContext objcxt;
 MemoryContext oldcxt;
 ArrayMetaState fakecache;

 /*
  * Allocate private context for expanded object.  We start by assuming
  * that the array won't be very large; but if it does grow a lot, don't
  * constrain aset.c's large-context behavior.
 */

 objcxt = AllocSetContextCreate(parentcontext,
           "expanded array",
           ALLOCSET_START_SMALL_SIZES);

 /* Set up expanded array header */
 eah = (ExpandedArrayHeader *)
  MemoryContextAlloc(objcxt, sizeof(ExpandedArrayHeader));

 EOH_init_header(&eah->hdr, &EA_methods, objcxt);
 eah->ea_magic = EA_MAGIC;

 /* If the source is an expanded array, we may be able to optimize */
 if (VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(arraydatum)))
 {
  ExpandedArrayHeader *oldeah = (ExpandedArrayHeader *) DatumGetEOHP(arraydatum);

  Assert(oldeah->ea_magic == EA_MAGIC);

  /*
   * Update caller's cache if provided; we don't need it this time, but
   * next call might be for a non-expanded source array.  Furthermore,
   * if the caller didn't provide a cache area, use some local storage
   * to cache anyway, thereby avoiding a catalog lookup in the case
   * where we fall through to the flat-copy code path.
 */

  if (metacache == NULL)
   metacache = &fakecache;
  metacache->element_type = oldeah->element_type;
  metacache->typlen = oldeah->typlen;
  metacache->typbyval = oldeah->typbyval;
  metacache->typalign = oldeah->typalign;

  /*
   * If element type is pass-by-value and we have a Datum-array
   * representation, just copy the source's metadata and Datum/isnull
   * arrays.  The original flat array, if present at all, adds no
   * additional information so we need not copy it.
 */

  if (oldeah->typbyval && oldeah->dvalues != NULL)
  {
   copy_byval_expanded_array(eah, oldeah);
   /* return a R/W pointer to the expanded array */
   return EOHPGetRWDatum(&eah->hdr);
  }

  /*
   * Otherwise, either we have only a flat representation or the
   * elements are pass-by-reference.  In either case, the best thing
   * seems to be to copy the source as a flat representation and then
   * deconstruct that later if necessary.  For the pass-by-ref case, we
   * could perhaps save some cycles with custom code that generates the
   * deconstructed representation in parallel with copying the values,
   * but it would be a lot of extra code for fairly marginal gain.  So,
   * fall through into the flat-source code path.
 */

 }

 /*
  * Detoast and copy source array into private context, as a flat array.
  *
  * Note that this coding risks leaking some memory in the private context
  * if we have to fetch data from a TOAST table; however, experimentation
  * says that the leak is minimal.  Doing it this way saves a copy step,
  * which seems worthwhile, especially if the array is large enough to need
  * external storage.
 */

 oldcxt = MemoryContextSwitchTo(objcxt);
 array = DatumGetArrayTypePCopy(arraydatum);
 MemoryContextSwitchTo(oldcxt);

 eah->ndims = ARR_NDIM(array);
 /* note these pointers point into the fvalue header! */
 eah->dims = ARR_DIMS(array);
 eah->lbound = ARR_LBOUND(array);

 /* Save array's element-type data for possible use later */
 eah->element_type = ARR_ELEMTYPE(array);
 if (metacache && metacache->element_type == eah->element_type)
 {
  /* We have a valid cache of representational data */
  eah->typlen = metacache->typlen;
  eah->typbyval = metacache->typbyval;
  eah->typalign = metacache->typalign;
 }
 else
 {
  /* No, so look it up */
  get_typlenbyvalalign(eah->element_type,
        &eah->typlen,
        &eah->typbyval,
        &eah->typalign);
  /* Update cache if provided */
  if (metacache)
  {
   metacache->element_type = eah->element_type;
   metacache->typlen = eah->typlen;
   metacache->typbyval = eah->typbyval;
   metacache->typalign = eah->typalign;
  }
 }

 /* we don't make a deconstructed representation now */
 eah->dvalues = NULL;
 eah->dnulls = NULL;
 eah->dvalueslen = 0;
 eah->nelems = 0;
 eah->flat_size = 0;

 /* remember we have a flat representation */
 eah->fvalue = array;
 eah->fstartptr = ARR_DATA_PTR(array);
 eah->fendptr = ((char *) array) + ARR_SIZE(array);

 /* return a R/W pointer to the expanded array */
 return EOHPGetRWDatum(&eah->hdr);
}

/*
 * helper for expand_array(): copy pass-by-value Datum-array representation
 */

static void
copy_byval_expanded_array(ExpandedArrayHeader *eah,
        ExpandedArrayHeader *oldeah)
{
 MemoryContext objcxt = eah->hdr.eoh_context;
 int   ndims = oldeah->ndims;
 int   dvalueslen = oldeah->dvalueslen;

 /* Copy array dimensionality information */
 eah->ndims = ndims;
 /* We can alloc both dimensionality arrays with one palloc */
 eah->dims = (int *) MemoryContextAlloc(objcxt, ndims * 2 * sizeof(int));
 eah->lbound = eah->dims + ndims;
 /* .. but don't assume the source's arrays are contiguous */
 memcpy(eah->dims, oldeah->dims, ndims * sizeof(int));
 memcpy(eah->lbound, oldeah->lbound, ndims * sizeof(int));

 /* Copy element-type data */
 eah->element_type = oldeah->element_type;
 eah->typlen = oldeah->typlen;
 eah->typbyval = oldeah->typbyval;
 eah->typalign = oldeah->typalign;

 /* Copy the deconstructed representation */
 eah->dvalues = (Datum *) MemoryContextAlloc(objcxt,
            dvalueslen * sizeof(Datum));
 memcpy(eah->dvalues, oldeah->dvalues, dvalueslen * sizeof(Datum));
 if (oldeah->dnulls)
 {
  eah->dnulls = (bool *) MemoryContextAlloc(objcxt,
              dvalueslen * sizeof(bool));
  memcpy(eah->dnulls, oldeah->dnulls, dvalueslen * sizeof(bool));
 }
 else
  eah->dnulls = NULL;
 eah->dvalueslen = dvalueslen;
 eah->nelems = oldeah->nelems;
 eah->flat_size = oldeah->flat_size;

 /* we don't make a flat representation */
 eah->fvalue = NULL;
 eah->fstartptr = NULL;
 eah->fendptr = NULL;
}

/*
 * get_flat_size method for expanded arrays
 */

static Size
EA_get_flat_size(ExpandedObjectHeader *eohptr)
{
 ExpandedArrayHeader *eah = (ExpandedArrayHeader *) eohptr;
 int   nelems;
 int   ndims;
 Datum    *dvalues;
 bool    *dnulls;
 Size  nbytes;
 int   i;

 Assert(eah->ea_magic == EA_MAGIC);

 /* Easy if we have a valid flattened value */
 if (eah->fvalue)
  return ARR_SIZE(eah->fvalue);

 /* If we have a cached size value, believe that */
 if (eah->flat_size)
  return eah->flat_size;

 /*
  * Compute space needed by examining dvalues/dnulls.  Note that the result
  * array will have a nulls bitmap if dnulls isn't NULL, even if the array
  * doesn't actually contain any nulls now.
 */

 nelems = eah->nelems;
 ndims = eah->ndims;
 Assert(nelems == ArrayGetNItems(ndims, eah->dims));
 dvalues = eah->dvalues;
 dnulls = eah->dnulls;
 nbytes = 0;
 for (i = 0; i < nelems; i++)
 {
  if (dnulls && dnulls[i])
   continue;
  nbytes = att_addlength_datum(nbytes, eah->typlen, dvalues[i]);
  nbytes = att_align_nominal(nbytes, eah->typalign);
  /* check for overflow of total request */
  if (!AllocSizeIsValid(nbytes))
   ereport(ERROR,
     (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
      errmsg("array size exceeds the maximum allowed (%d)",
       (int) MaxAllocSize)));
 }

 if (dnulls)
  nbytes += ARR_OVERHEAD_WITHNULLS(ndims, nelems);
 else
  nbytes += ARR_OVERHEAD_NONULLS(ndims);

 /* cache for next time */
 eah->flat_size = nbytes;

 return nbytes;
}

/*
 * flatten_into method for expanded arrays
 */

static void
EA_flatten_into(ExpandedObjectHeader *eohptr,
    void *result, Size allocated_size)
{
 ExpandedArrayHeader *eah = (ExpandedArrayHeader *) eohptr;
 ArrayType  *aresult = (ArrayType *) result;
 int   nelems;
 int   ndims;
 int32  dataoffset;

 Assert(eah->ea_magic == EA_MAGIC);

 /* Easy if we have a valid flattened value */
 if (eah->fvalue)
 {
  Assert(allocated_size == ARR_SIZE(eah->fvalue));
  memcpy(result, eah->fvalue, allocated_size);
  return;
 }

 /* Else allocation should match previous get_flat_size result */
 Assert(allocated_size == eah->flat_size);

 /* Fill result array from dvalues/dnulls */
 nelems = eah->nelems;
 ndims = eah->ndims;

 if (eah->dnulls)
  dataoffset = ARR_OVERHEAD_WITHNULLS(ndims, nelems);
 else
  dataoffset = 0;   /* marker for no null bitmap */

 /* We must ensure that any pad space is zero-filled */
 memset(aresult, 0, allocated_size);

 SET_VARSIZE(aresult, allocated_size);
 aresult->ndim = ndims;
 aresult->dataoffset = dataoffset;
 aresult->elemtype = eah->element_type;
 memcpy(ARR_DIMS(aresult), eah->dims, ndims * sizeof(int));
 memcpy(ARR_LBOUND(aresult), eah->lbound, ndims * sizeof(int));

 CopyArrayEls(aresult,
     eah->dvalues, eah->dnulls, nelems,
     eah->typlen, eah->typbyval, eah->typalign,
     false);
}

/*
 * Argument fetching support code
 */


/*
 * DatumGetExpandedArray: get a writable expanded array from an input argument
 *
 * Caution: if the input is a read/write pointer, this returns the input
 * argument; so callers must be sure that their changes are "safe", that is
 * they cannot leave the array in a corrupt state.
 */

ExpandedArrayHeader *
DatumGetExpandedArray(Datum d)
{
 /* If it's a writable expanded array already, just return it */
 if (VARATT_IS_EXTERNAL_EXPANDED_RW(DatumGetPointer(d)))
 {
  ExpandedArrayHeader *eah = (ExpandedArrayHeader *) DatumGetEOHP(d);

  Assert(eah->ea_magic == EA_MAGIC);
  return eah;
 }

 /* Else expand the hard way */
 d = expand_array(d, CurrentMemoryContext, NULL);
 return (ExpandedArrayHeader *) DatumGetEOHP(d);
}

/*
 * As above, when caller has the ability to cache element type info
 */

ExpandedArrayHeader *
DatumGetExpandedArrayX(Datum d, ArrayMetaState *metacache)
{
 /* If it's a writable expanded array already, just return it */
 if (VARATT_IS_EXTERNAL_EXPANDED_RW(DatumGetPointer(d)))
 {
  ExpandedArrayHeader *eah = (ExpandedArrayHeader *) DatumGetEOHP(d);

  Assert(eah->ea_magic == EA_MAGIC);
  /* Update cache if provided */
  if (metacache)
  {
   metacache->element_type = eah->element_type;
   metacache->typlen = eah->typlen;
   metacache->typbyval = eah->typbyval;
   metacache->typalign = eah->typalign;
  }
  return eah;
 }

 /* Else expand using caller's cache if any */
 d = expand_array(d, CurrentMemoryContext, metacache);
 return (ExpandedArrayHeader *) DatumGetEOHP(d);
}

/*
 * DatumGetAnyArrayP: return either an expanded array or a detoasted varlena
 * array.  The result must not be modified in-place.
 */

AnyArrayType *
DatumGetAnyArrayP(Datum d)
{
 ExpandedArrayHeader *eah;

 /*
  * If it's an expanded array (RW or RO), return the header pointer.
 */

 if (VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(d)))
 {
  eah = (ExpandedArrayHeader *) DatumGetEOHP(d);
  Assert(eah->ea_magic == EA_MAGIC);
  return (AnyArrayType *) eah;
 }

 /* Else do regular detoasting as needed */
 return (AnyArrayType *) PG_DETOAST_DATUM(d);
}

/*
 * Create the Datum/isnull representation of an expanded array object
 * if we didn't do so previously
 */

void
deconstruct_expanded_array(ExpandedArrayHeader *eah)
{
 if (eah->dvalues == NULL)
 {
  MemoryContext oldcxt = MemoryContextSwitchTo(eah->hdr.eoh_context);
  Datum    *dvalues;
  bool    *dnulls;
  int   nelems;

  dnulls = NULL;
  deconstruct_array(eah->fvalue,
        eah->element_type,
        eah->typlen, eah->typbyval, eah->typalign,
        &dvalues,
        ARR_HASNULL(eah->fvalue) ? &dnulls : NULL,
        &nelems);

  /*
   * Update header only after successful completion of this step.  If
   * deconstruct_array fails partway through, worst consequence is some
   * leaked memory in the object's context.  If the caller fails at a
   * later point, that's fine, since the deconstructed representation is
   * valid anyhow.
 */

  eah->dvalues = dvalues;
  eah->dnulls = dnulls;
  eah->dvalueslen = eah->nelems = nelems;
  MemoryContextSwitchTo(oldcxt);
 }
}

Messung V0.5 in Prozent
C=94 H=93 G=93

[Verzeichnis aufwärts0.19unsichere VerbindungÜbersetzung europäischer Sprachen durch Browser2026-08-08]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=141584
#Domains=752002