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-2024, 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 postgres.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 42114 : EOHPGetRWDatum(const struct ExpandedObjectHeader *eohptr) 140 : { 141 42114 : return PointerGetDatum(eohptr->eoh_rw_ptr); 142 : } 143 : 144 : static inline Datum 145 31212 : EOHPGetRODatum(const struct ExpandedObjectHeader *eohptr) 146 : { 147 31212 : 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 */