LCOV - code coverage report
Current view: top level - src/include/utils - expandeddatum.h (source / functions) Coverage Total Hit
Test: Code coverage Lines: 100.0 % 4 4
Test Date: 2026-01-26 10:56:24 Functions: 100.0 % 2 2
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * expandeddatum.h
       4              :  *        Declarations for access to "expanded" value representations.
       5              :  *
       6              :  * Complex data types, particularly container types such as arrays and
       7              :  * records, usually have on-disk representations that are compact but not
       8              :  * especially convenient to modify.  What's more, when we do modify them,
       9              :  * having to recopy all the rest of the value can be extremely inefficient.
      10              :  * Therefore, we provide a notion of an "expanded" representation that is used
      11              :  * only in memory and is optimized more for computation than storage.
      12              :  * The format appearing on disk is called the data type's "flattened"
      13              :  * representation, since it is required to be a contiguous blob of bytes --
      14              :  * but the type can have an expanded representation that is not.  Data types
      15              :  * must provide means to translate an expanded representation back to
      16              :  * flattened form.
      17              :  *
      18              :  * An expanded object is meant to survive across multiple operations, but
      19              :  * not to be enormously long-lived; for example it might be a local variable
      20              :  * in a PL/pgSQL procedure.  So its extra bulk compared to the on-disk format
      21              :  * is a worthwhile trade-off.
      22              :  *
      23              :  * References to expanded objects are a type of TOAST pointer.
      24              :  * Because of longstanding conventions in Postgres, this means that the
      25              :  * flattened form of such an object must always be a varlena object.
      26              :  * Fortunately that's no restriction in practice.
      27              :  *
      28              :  * There are actually two kinds of TOAST pointers for expanded objects:
      29              :  * read-only and read-write pointers.  Possession of one of the latter
      30              :  * authorizes a function to modify the value in-place rather than copying it
      31              :  * as would normally be required.  Functions should always return a read-write
      32              :  * pointer to any new expanded object they create.  Functions that modify an
      33              :  * argument value in-place must take care that they do not corrupt the old
      34              :  * value if they fail partway through.
      35              :  *
      36              :  *
      37              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
      38              :  * Portions Copyright (c) 1994, Regents of the University of California
      39              :  *
      40              :  * src/include/utils/expandeddatum.h
      41              :  *
      42              :  *-------------------------------------------------------------------------
      43              :  */
      44              : #ifndef EXPANDEDDATUM_H
      45              : #define EXPANDEDDATUM_H
      46              : 
      47              : #include "varatt.h"
      48              : 
      49              : /* Size of an EXTERNAL datum that contains a pointer to an expanded object */
      50              : #define EXPANDED_POINTER_SIZE (VARHDRSZ_EXTERNAL + sizeof(varatt_expanded))
      51              : 
      52              : /*
      53              :  * "Methods" that must be provided for any expanded object.
      54              :  *
      55              :  * get_flat_size: compute space needed for flattened representation (total,
      56              :  * including header).
      57              :  *
      58              :  * flatten_into: construct flattened representation in the caller-allocated
      59              :  * space at *result, of size allocated_size (which will always be the result
      60              :  * of a preceding get_flat_size call; it's passed for cross-checking).
      61              :  *
      62              :  * The flattened representation must be a valid in-line, non-compressed,
      63              :  * 4-byte-header varlena object.
      64              :  *
      65              :  * Note: construction of a heap tuple from an expanded datum calls
      66              :  * get_flat_size twice, so it's worthwhile to make sure that that doesn't
      67              :  * incur too much overhead.
      68              :  */
      69              : typedef Size (*EOM_get_flat_size_method) (ExpandedObjectHeader *eohptr);
      70              : typedef void (*EOM_flatten_into_method) (ExpandedObjectHeader *eohptr,
      71              :                                                                                  void *result, Size allocated_size);
      72              : 
      73              : /* Struct of function pointers for an expanded object's methods */
      74              : typedef struct ExpandedObjectMethods
      75              : {
      76              :         EOM_get_flat_size_method get_flat_size;
      77              :         EOM_flatten_into_method flatten_into;
      78              : } ExpandedObjectMethods;
      79              : 
      80              : /*
      81              :  * Every expanded object must contain this header; typically the header
      82              :  * is embedded in some larger struct that adds type-specific fields.
      83              :  *
      84              :  * It is presumed that the header object and all subsidiary data are stored
      85              :  * in eoh_context, so that the object can be freed by deleting that context,
      86              :  * or its storage lifespan can be altered by reparenting the context.
      87              :  * (In principle the object could own additional resources, such as malloc'd
      88              :  * storage, and use a memory context reset callback to free them upon reset or
      89              :  * deletion of eoh_context.)
      90              :  *
      91              :  * We set up two TOAST pointers within the standard header, one read-write
      92              :  * and one read-only.  This allows functions to return either kind of pointer
      93              :  * without making an additional allocation, and in particular without worrying
      94              :  * whether a separately palloc'd object would have sufficient lifespan.
      95              :  * But note that these pointers are just a convenience; a pointer object
      96              :  * appearing somewhere else would still be legal.
      97              :  *
      98              :  * The typedef declaration for this appears in varatt.h.
      99              :  */
     100              : struct ExpandedObjectHeader
     101              : {
     102              :         /* Phony varlena header */
     103              :         int32           vl_len_;                /* always EOH_HEADER_MAGIC, see below */
     104              : 
     105              :         /* Pointer to methods required for object type */
     106              :         const ExpandedObjectMethods *eoh_methods;
     107              : 
     108              :         /* Memory context containing this header and subsidiary data */
     109              :         MemoryContext eoh_context;
     110              : 
     111              :         /* Standard R/W TOAST pointer for this object is kept here */
     112              :         char            eoh_rw_ptr[EXPANDED_POINTER_SIZE];
     113              : 
     114              :         /* Standard R/O TOAST pointer for this object is kept here */
     115              :         char            eoh_ro_ptr[EXPANDED_POINTER_SIZE];
     116              : };
     117              : 
     118              : /*
     119              :  * Particularly for read-only functions, it is handy to be able to work with
     120              :  * either regular "flat" varlena inputs or expanded inputs of the same data
     121              :  * type.  To allow determining which case an argument-fetching function has
     122              :  * returned, the first int32 of an ExpandedObjectHeader always contains -1
     123              :  * (EOH_HEADER_MAGIC to the code).  This works since no 4-byte-header varlena
     124              :  * could have that as its first 4 bytes.  Caution: we could not reliably tell
     125              :  * the difference between an ExpandedObjectHeader and a short-header object
     126              :  * with this trick.  However, it works fine if the argument fetching code
     127              :  * always returns either a 4-byte-header flat object or an expanded object.
     128              :  */
     129              : #define EOH_HEADER_MAGIC (-1)
     130              : #define VARATT_IS_EXPANDED_HEADER(PTR) \
     131              :         (((varattrib_4b *) (PTR))->va_4byte.va_header == (uint32) EOH_HEADER_MAGIC)
     132              : 
     133              : /*
     134              :  * Generic support functions for expanded objects.
     135              :  * (More of these might be worth inlining later.)
     136              :  */
     137              : 
     138              : static inline Datum
     139         5482 : EOHPGetRWDatum(const struct ExpandedObjectHeader *eohptr)
     140              : {
     141         5482 :         return PointerGetDatum(eohptr->eoh_rw_ptr);
     142              : }
     143              : 
     144              : static inline Datum
     145         4968 : EOHPGetRODatum(const struct ExpandedObjectHeader *eohptr)
     146              : {
     147         4968 :         return PointerGetDatum(eohptr->eoh_ro_ptr);
     148              : }
     149              : 
     150              : /* Does the Datum represent a writable expanded object? */
     151              : #define DatumIsReadWriteExpandedObject(d, isnull, typlen) \
     152              :         (((isnull) || (typlen) != -1) ? false : \
     153              :          VARATT_IS_EXTERNAL_EXPANDED_RW(DatumGetPointer(d)))
     154              : 
     155              : #define MakeExpandedObjectReadOnly(d, isnull, typlen) \
     156              :         (((isnull) || (typlen) != -1) ? (d) : \
     157              :          MakeExpandedObjectReadOnlyInternal(d))
     158              : 
     159              : extern ExpandedObjectHeader *DatumGetEOHP(Datum d);
     160              : extern void EOH_init_header(ExpandedObjectHeader *eohptr,
     161              :                                                         const ExpandedObjectMethods *methods,
     162              :                                                         MemoryContext obj_context);
     163              : extern Size EOH_get_flat_size(ExpandedObjectHeader *eohptr);
     164              : extern void EOH_flatten_into(ExpandedObjectHeader *eohptr,
     165              :                                                          void *result, Size allocated_size);
     166              : extern Datum MakeExpandedObjectReadOnlyInternal(Datum d);
     167              : extern Datum TransferExpandedObject(Datum d, MemoryContext new_parent);
     168              : extern void DeleteExpandedObject(Datum d);
     169              : 
     170              : #endif                                                  /* EXPANDEDDATUM_H */
        

Generated by: LCOV version 2.3.2-1