codekingpro/portable-devtools
115k
1/*-------------------------------------------------------------------------2 *3 * expandedrecord.h4 * Declarations for composite expanded objects.5 *6 * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group7 * Portions Copyright (c) 1994, Regents of the University of California8 *9 * src/include/utils/expandedrecord.h10 *11 *-------------------------------------------------------------------------12 */13#ifndef EXPANDEDRECORD_H14#define EXPANDEDRECORD_H15 16#include "access/htup.h"17#include "access/tupdesc.h"18#include "fmgr.h"19#include "utils/expandeddatum.h"20 21 22/*23 * An expanded record is contained within a private memory context (as24 * all expanded objects must be) and has a control structure as below.25 *26 * The expanded record might contain a regular "flat" tuple if that was the27 * original input and we've not modified it. Otherwise, the contents are28 * represented by Datum/isnull arrays plus type information. We could also29 * have both forms, if we've deconstructed the original tuple for access30 * purposes but not yet changed it. For pass-by-reference field types, the31 * Datums would point into the flat tuple in this situation. Once we start32 * modifying tuple fields, new pass-by-ref fields are separately palloc'd33 * within the memory context.34 *35 * It's possible to build an expanded record that references a "flat" tuple36 * stored externally, if the caller can guarantee that that tuple will not37 * change for the lifetime of the expanded record. (This frammish is mainly38 * meant to avoid unnecessary data copying in trigger functions.)39 */40#define ER_MAGIC 1384727874 /* ID for debugging crosschecks */41 42typedef struct ExpandedRecordHeader43{44 /* Standard header for expanded objects */45 ExpandedObjectHeader hdr;46 47 /* Magic value identifying an expanded record (for debugging only) */48 int er_magic;49 50 /* Assorted flag bits */51 int flags;52#define ER_FLAG_FVALUE_VALID 0x0001 /* fvalue is up to date? */53#define ER_FLAG_FVALUE_ALLOCED 0x0002 /* fvalue is local storage? */54#define ER_FLAG_DVALUES_VALID 0x0004 /* dvalues/dnulls are up to date? */55#define ER_FLAG_DVALUES_ALLOCED 0x0008 /* any field values local storage? */56#define ER_FLAG_HAVE_EXTERNAL 0x0010 /* any field values are external? */57#define ER_FLAG_TUPDESC_ALLOCED 0x0020 /* tupdesc is local storage? */58#define ER_FLAG_IS_DOMAIN 0x0040 /* er_decltypeid is domain? */59#define ER_FLAG_IS_DUMMY 0x0080 /* this header is dummy (see below) */60/* flag bits that are not to be cleared when replacing tuple data: */61#define ER_FLAGS_NON_DATA \62 (ER_FLAG_TUPDESC_ALLOCED | ER_FLAG_IS_DOMAIN | ER_FLAG_IS_DUMMY)63 64 /* Declared type of the record variable (could be a domain type) */65 Oid er_decltypeid;66 67 /*68 * Actual composite type/typmod; never a domain (if ER_FLAG_IS_DOMAIN,69 * these identify the composite base type). These will match70 * er_tupdesc->tdtypeid/tdtypmod, as well as the header fields of71 * composite datums made from or stored in this expanded record.72 */73 Oid er_typeid; /* type OID of the composite type */74 int32 er_typmod; /* typmod of the composite type */75 76 /*77 * Tuple descriptor, if we have one, else NULL. This may point to a78 * reference-counted tupdesc originally belonging to the typcache, in79 * which case we use a memory context reset callback to release the80 * refcount. It can also be locally allocated in this object's private81 * context (in which case ER_FLAG_TUPDESC_ALLOCED is set).82 */83 TupleDesc er_tupdesc;84 85 /*86 * Unique-within-process identifier for the tupdesc (see typcache.h). This87 * field will never be equal to INVALID_TUPLEDESC_IDENTIFIER.88 */89 uint64 er_tupdesc_id;90 91 /*92 * If we have a Datum-array representation of the record, it's kept here;93 * else ER_FLAG_DVALUES_VALID is not set, and dvalues/dnulls may be NULL94 * if they've not yet been allocated. If allocated, the dvalues and95 * dnulls arrays are palloc'd within the object private context, and are96 * of length matching er_tupdesc->natts. For pass-by-ref field types,97 * dvalues entries might point either into the fstartptr..fendptr area, or98 * to separately palloc'd chunks.99 */100 Datum *dvalues; /* array of Datums */101 bool *dnulls; /* array of is-null flags for Datums */102 int nfields; /* length of above arrays */103 104 /*105 * flat_size is the current space requirement for the flat equivalent of106 * the expanded record, if known; otherwise it's 0. We store this to make107 * consecutive calls of get_flat_size cheap. If flat_size is not 0, the108 * component values data_len, hoff, and hasnull must be valid too.109 */110 Size flat_size;111 112 Size data_len; /* data len within flat_size */113 int hoff; /* header offset */114 bool hasnull; /* null bitmap needed? */115 116 /*117 * fvalue points to the flat representation if we have one, else it is118 * NULL. If the flat representation is valid (up to date) then119 * ER_FLAG_FVALUE_VALID is set. Even if we've outdated the flat120 * representation due to changes of user fields, it can still be used to121 * fetch system column values. If we have a flat representation then122 * fstartptr/fendptr point to the start and end+1 of its data area; this123 * is so that we can tell which Datum pointers point into the flat124 * representation rather than being pointers to separately palloc'd data.125 */126 HeapTuple fvalue; /* might or might not be private storage */127 char *fstartptr; /* start of its data area */128 char *fendptr; /* end+1 of its data area */129 130 /* Some operations on the expanded record need a short-lived context */131 MemoryContext er_short_term_cxt; /* short-term memory context */132 133 /* Working state for domain checking, used if ER_FLAG_IS_DOMAIN is set */134 struct ExpandedRecordHeader *er_dummy_header; /* dummy record header */135 void *er_domaininfo; /* cache space for domain_check() */136 137 /* Callback info (it's active if er_mcb.arg is not NULL) */138 MemoryContextCallback er_mcb;139} ExpandedRecordHeader;140 141/* fmgr functions and macros for expanded record objects */142static inline Datum143ExpandedRecordGetDatum(const ExpandedRecordHeader *erh)144{145 return EOHPGetRWDatum(&erh->hdr);146}147 148static inline Datum149ExpandedRecordGetRODatum(const ExpandedRecordHeader *erh)150{151 return EOHPGetRODatum(&erh->hdr);152}153 154#define PG_GETARG_EXPANDED_RECORD(n) DatumGetExpandedRecord(PG_GETARG_DATUM(n))155#define PG_RETURN_EXPANDED_RECORD(x) PG_RETURN_DATUM(ExpandedRecordGetDatum(x))156 157/* assorted other macros */158#define ExpandedRecordIsEmpty(erh) \159 (((erh)->flags & (ER_FLAG_DVALUES_VALID | ER_FLAG_FVALUE_VALID)) == 0)160#define ExpandedRecordIsDomain(erh) \161 (((erh)->flags & ER_FLAG_IS_DOMAIN) != 0)162 163/* this can substitute for TransferExpandedObject() when we already have erh */164#define TransferExpandedRecord(erh, cxt) \165 MemoryContextSetParent((erh)->hdr.eoh_context, cxt)166 167/* information returned by expanded_record_lookup_field() */168typedef struct ExpandedRecordFieldInfo169{170 int fnumber; /* field's attr number in record */171 Oid ftypeid; /* field's type/typmod info */172 int32 ftypmod;173 Oid fcollation; /* field's collation if any */174} ExpandedRecordFieldInfo;175 176/*177 * prototypes for functions defined in expandedrecord.c178 */179extern ExpandedRecordHeader *make_expanded_record_from_typeid(Oid type_id, int32 typmod,180 MemoryContext parentcontext);181extern ExpandedRecordHeader *make_expanded_record_from_tupdesc(TupleDesc tupdesc,182 MemoryContext parentcontext);183extern ExpandedRecordHeader *make_expanded_record_from_exprecord(ExpandedRecordHeader *olderh,184 MemoryContext parentcontext);185extern void expanded_record_set_tuple(ExpandedRecordHeader *erh,186 HeapTuple tuple, bool copy, bool expand_external);187extern Datum make_expanded_record_from_datum(Datum recorddatum,188 MemoryContext parentcontext);189extern TupleDesc expanded_record_fetch_tupdesc(ExpandedRecordHeader *erh);190extern HeapTuple expanded_record_get_tuple(ExpandedRecordHeader *erh);191extern ExpandedRecordHeader *DatumGetExpandedRecord(Datum d);192extern void deconstruct_expanded_record(ExpandedRecordHeader *erh);193extern bool expanded_record_lookup_field(ExpandedRecordHeader *erh,194 const char *fieldname,195 ExpandedRecordFieldInfo *finfo);196extern Datum expanded_record_fetch_field(ExpandedRecordHeader *erh, int fnumber,197 bool *isnull);198extern void expanded_record_set_field_internal(ExpandedRecordHeader *erh,199 int fnumber,200 Datum newValue, bool isnull,201 bool expand_external,202 bool check_constraints);203extern void expanded_record_set_fields(ExpandedRecordHeader *erh,204 const Datum *newValues, const bool *isnulls,205 bool expand_external);206 207/* outside code should never call expanded_record_set_field_internal as such */208#define expanded_record_set_field(erh, fnumber, newValue, isnull, expand_external) \209 expanded_record_set_field_internal(erh, fnumber, newValue, isnull, expand_external, true)210 211/*212 * Inline-able fast cases. The expanded_record_fetch_xxx functions above213 * handle the general cases.214 */215 216/* Get the tupdesc for the expanded record's actual type */217static inline TupleDesc218expanded_record_get_tupdesc(ExpandedRecordHeader *erh)219{220 if (likely(erh->er_tupdesc != NULL))221 return erh->er_tupdesc;222 else223 return expanded_record_fetch_tupdesc(erh);224}225 226/* Get value of record field */227static inline Datum228expanded_record_get_field(ExpandedRecordHeader *erh, int fnumber,229 bool *isnull)230{231 if ((erh->flags & ER_FLAG_DVALUES_VALID) &&232 likely(fnumber > 0 && fnumber <= erh->nfields))233 {234 *isnull = erh->dnulls[fnumber - 1];235 return erh->dvalues[fnumber - 1];236 }237 else238 return expanded_record_fetch_field(erh, fnumber, isnull);239}240 241#endif /* EXPANDEDRECORD_H */242 