PostgreSQL Source Code  git master
expandedrecord.h
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * expandedrecord.h
4  * Declarations for composite expanded objects.
5  *
6  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  * src/include/utils/expandedrecord.h
10  *
11  *-------------------------------------------------------------------------
12  */
13 #ifndef EXPANDEDRECORD_H
14 #define EXPANDEDRECORD_H
15 
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 (as
24  * 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 the
27  * original input and we've not modified it. Otherwise, the contents are
28  * represented by Datum/isnull arrays plus type information. We could also
29  * have both forms, if we've deconstructed the original tuple for access
30  * purposes but not yet changed it. For pass-by-reference field types, the
31  * Datums would point into the flat tuple in this situation. Once we start
32  * modifying tuple fields, new pass-by-ref fields are separately palloc'd
33  * within the memory context.
34  *
35  * It's possible to build an expanded record that references a "flat" tuple
36  * stored externally, if the caller can guarantee that that tuple will not
37  * change for the lifetime of the expanded record. (This frammish is mainly
38  * meant to avoid unnecessary data copying in trigger functions.)
39  */
40 #define ER_MAGIC 1384727874 /* ID for debugging crosschecks */
41 
42 typedef struct ExpandedRecordHeader
43 {
44  /* Standard header for expanded objects */
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) */
66 
67  /*
68  * Actual composite type/typmod; never a domain (if ER_FLAG_IS_DOMAIN,
69  * these identify the composite base type). These will match
70  * er_tupdesc->tdtypeid/tdtypmod, as well as the header fields of
71  * 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 a
78  * reference-counted tupdesc originally belonging to the typcache, in
79  * which case we use a memory context reset callback to release the
80  * refcount. It can also be locally allocated in this object's private
81  * context (in which case ER_FLAG_TUPDESC_ALLOCED is set).
82  */
84 
85  /*
86  * Unique-within-process identifier for the tupdesc (see typcache.h). This
87  * 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 NULL
94  * if they've not yet been allocated. If allocated, the dvalues and
95  * dnulls arrays are palloc'd within the object private context, and are
96  * of length matching er_tupdesc->natts. For pass-by-ref field types,
97  * dvalues entries might point either into the fstartptr..fendptr area, or
98  * 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 of
106  * the expanded record, if known; otherwise it's 0. We store this to make
107  * consecutive calls of get_flat_size cheap. If flat_size is not 0, the
108  * component values data_len, hoff, and hasnull must be valid too.
109  */
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 is
118  * NULL. If the flat representation is valid (up to date) then
119  * ER_FLAG_FVALUE_VALID is set. Even if we've outdated the flat
120  * representation due to changes of user fields, it can still be used to
121  * fetch system column values. If we have a flat representation then
122  * fstartptr/fendptr point to the start and end+1 of its data area; this
123  * is so that we can tell which Datum pointers point into the flat
124  * 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) */
140 
141 /* fmgr functions and macros for expanded record objects */
142 static inline Datum
144 {
145  return EOHPGetRWDatum(&erh->hdr);
146 }
147 
148 static inline Datum
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() */
169 {
170  int fnumber; /* field's attr number in record */
171  Oid ftypeid; /* field's type/typmod info */
173  Oid fcollation; /* field's collation if any */
175 
176 /*
177  * prototypes for functions defined in expandedrecord.c
178  */
180  MemoryContext parentcontext);
182  MemoryContext parentcontext);
184  MemoryContext parentcontext);
186  HeapTuple tuple, bool copy, bool expand_external);
187 extern Datum make_expanded_record_from_datum(Datum recorddatum,
188  MemoryContext parentcontext);
194  const char *fieldname,
195  ExpandedRecordFieldInfo *finfo);
197  bool *isnull);
199  int fnumber,
200  Datum newValue, bool isnull,
201  bool expand_external,
202  bool check_constraints);
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 above
213  * handle the general cases.
214  */
215 
216 /* Get the tupdesc for the expanded record's actual type */
217 static inline TupleDesc
219 {
220  if (likely(erh->er_tupdesc != NULL))
221  return erh->er_tupdesc;
222  else
223  return expanded_record_fetch_tupdesc(erh);
224 }
225 
226 /* Get value of record field */
227 static inline Datum
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  else
238  return expanded_record_fetch_field(erh, fnumber, isnull);
239 }
240 
241 #endif /* EXPANDEDRECORD_H */
#define likely(x)
Definition: c.h:310
signed int int32
Definition: c.h:494
size_t Size
Definition: c.h:605
static Datum EOHPGetRWDatum(const struct ExpandedObjectHeader *eohptr)
static Datum EOHPGetRODatum(const struct ExpandedObjectHeader *eohptr)
ExpandedRecordHeader * make_expanded_record_from_tupdesc(TupleDesc tupdesc, MemoryContext parentcontext)
ExpandedRecordHeader * make_expanded_record_from_typeid(Oid type_id, int32 typmod, MemoryContext parentcontext)
struct ExpandedRecordFieldInfo ExpandedRecordFieldInfo
static Datum ExpandedRecordGetDatum(const ExpandedRecordHeader *erh)
static Datum expanded_record_get_field(ExpandedRecordHeader *erh, int fnumber, bool *isnull)
static Datum ExpandedRecordGetRODatum(const ExpandedRecordHeader *erh)
void expanded_record_set_field_internal(ExpandedRecordHeader *erh, int fnumber, Datum newValue, bool isnull, bool expand_external, bool check_constraints)
bool expanded_record_lookup_field(ExpandedRecordHeader *erh, const char *fieldname, ExpandedRecordFieldInfo *finfo)
Datum expanded_record_fetch_field(ExpandedRecordHeader *erh, int fnumber, bool *isnull)
#define ER_FLAG_DVALUES_VALID
static TupleDesc expanded_record_get_tupdesc(ExpandedRecordHeader *erh)
Datum make_expanded_record_from_datum(Datum recorddatum, MemoryContext parentcontext)
ExpandedRecordHeader * make_expanded_record_from_exprecord(ExpandedRecordHeader *olderh, MemoryContext parentcontext)
TupleDesc expanded_record_fetch_tupdesc(ExpandedRecordHeader *erh)
void expanded_record_set_tuple(ExpandedRecordHeader *erh, HeapTuple tuple, bool copy, bool expand_external)
HeapTuple expanded_record_get_tuple(ExpandedRecordHeader *erh)
struct ExpandedRecordHeader ExpandedRecordHeader
ExpandedRecordHeader * DatumGetExpandedRecord(Datum d)
void deconstruct_expanded_record(ExpandedRecordHeader *erh)
void expanded_record_set_fields(ExpandedRecordHeader *erh, const Datum *newValues, const bool *isnulls, bool expand_external)
uintptr_t Datum
Definition: postgres.h:64
unsigned int Oid
Definition: postgres_ext.h:31
MemoryContext er_short_term_cxt
ExpandedObjectHeader hdr
MemoryContextCallback er_mcb
struct ExpandedRecordHeader * er_dummy_header