expandedrecord.h 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. /*-------------------------------------------------------------------------
  2. *
  3. * expandedrecord.h
  4. * Declarations for composite expanded objects.
  5. *
  6. * Portions Copyright (c) 1996-2022, 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. #include "access/htup.h"
  16. #include "access/tupdesc.h"
  17. #include "fmgr.h"
  18. #include "utils/expandeddatum.h"
  19. /*
  20. * An expanded record is contained within a private memory context (as
  21. * all expanded objects must be) and has a control structure as below.
  22. *
  23. * The expanded record might contain a regular "flat" tuple if that was the
  24. * original input and we've not modified it. Otherwise, the contents are
  25. * represented by Datum/isnull arrays plus type information. We could also
  26. * have both forms, if we've deconstructed the original tuple for access
  27. * purposes but not yet changed it. For pass-by-reference field types, the
  28. * Datums would point into the flat tuple in this situation. Once we start
  29. * modifying tuple fields, new pass-by-ref fields are separately palloc'd
  30. * within the memory context.
  31. *
  32. * It's possible to build an expanded record that references a "flat" tuple
  33. * stored externally, if the caller can guarantee that that tuple will not
  34. * change for the lifetime of the expanded record. (This frammish is mainly
  35. * meant to avoid unnecessary data copying in trigger functions.)
  36. */
  37. #define ER_MAGIC 1384727874 /* ID for debugging crosschecks */
  38. typedef struct ExpandedRecordHeader
  39. {
  40. /* Standard header for expanded objects */
  41. ExpandedObjectHeader hdr;
  42. /* Magic value identifying an expanded record (for debugging only) */
  43. int er_magic;
  44. /* Assorted flag bits */
  45. int flags;
  46. #define ER_FLAG_FVALUE_VALID 0x0001 /* fvalue is up to date? */
  47. #define ER_FLAG_FVALUE_ALLOCED 0x0002 /* fvalue is local storage? */
  48. #define ER_FLAG_DVALUES_VALID 0x0004 /* dvalues/dnulls are up to date? */
  49. #define ER_FLAG_DVALUES_ALLOCED 0x0008 /* any field values local storage? */
  50. #define ER_FLAG_HAVE_EXTERNAL 0x0010 /* any field values are external? */
  51. #define ER_FLAG_TUPDESC_ALLOCED 0x0020 /* tupdesc is local storage? */
  52. #define ER_FLAG_IS_DOMAIN 0x0040 /* er_decltypeid is domain? */
  53. #define ER_FLAG_IS_DUMMY 0x0080 /* this header is dummy (see below) */
  54. /* flag bits that are not to be cleared when replacing tuple data: */
  55. #define ER_FLAGS_NON_DATA \
  56. (ER_FLAG_TUPDESC_ALLOCED | ER_FLAG_IS_DOMAIN | ER_FLAG_IS_DUMMY)
  57. /* Declared type of the record variable (could be a domain type) */
  58. Oid er_decltypeid;
  59. /*
  60. * Actual composite type/typmod; never a domain (if ER_FLAG_IS_DOMAIN,
  61. * these identify the composite base type). These will match
  62. * er_tupdesc->tdtypeid/tdtypmod, as well as the header fields of
  63. * composite datums made from or stored in this expanded record.
  64. */
  65. Oid er_typeid; /* type OID of the composite type */
  66. int32 er_typmod; /* typmod of the composite type */
  67. /*
  68. * Tuple descriptor, if we have one, else NULL. This may point to a
  69. * reference-counted tupdesc originally belonging to the typcache, in
  70. * which case we use a memory context reset callback to release the
  71. * refcount. It can also be locally allocated in this object's private
  72. * context (in which case ER_FLAG_TUPDESC_ALLOCED is set).
  73. */
  74. TupleDesc er_tupdesc;
  75. /*
  76. * Unique-within-process identifier for the tupdesc (see typcache.h). This
  77. * field will never be equal to INVALID_TUPLEDESC_IDENTIFIER.
  78. */
  79. uint64 er_tupdesc_id;
  80. /*
  81. * If we have a Datum-array representation of the record, it's kept here;
  82. * else ER_FLAG_DVALUES_VALID is not set, and dvalues/dnulls may be NULL
  83. * if they've not yet been allocated. If allocated, the dvalues and
  84. * dnulls arrays are palloc'd within the object private context, and are
  85. * of length matching er_tupdesc->natts. For pass-by-ref field types,
  86. * dvalues entries might point either into the fstartptr..fendptr area, or
  87. * to separately palloc'd chunks.
  88. */
  89. Datum *dvalues; /* array of Datums */
  90. bool *dnulls; /* array of is-null flags for Datums */
  91. int nfields; /* length of above arrays */
  92. /*
  93. * flat_size is the current space requirement for the flat equivalent of
  94. * the expanded record, if known; otherwise it's 0. We store this to make
  95. * consecutive calls of get_flat_size cheap. If flat_size is not 0, the
  96. * component values data_len, hoff, and hasnull must be valid too.
  97. */
  98. Size flat_size;
  99. Size data_len; /* data len within flat_size */
  100. int hoff; /* header offset */
  101. bool hasnull; /* null bitmap needed? */
  102. /*
  103. * fvalue points to the flat representation if we have one, else it is
  104. * NULL. If the flat representation is valid (up to date) then
  105. * ER_FLAG_FVALUE_VALID is set. Even if we've outdated the flat
  106. * representation due to changes of user fields, it can still be used to
  107. * fetch system column values. If we have a flat representation then
  108. * fstartptr/fendptr point to the start and end+1 of its data area; this
  109. * is so that we can tell which Datum pointers point into the flat
  110. * representation rather than being pointers to separately palloc'd data.
  111. */
  112. HeapTuple fvalue; /* might or might not be private storage */
  113. char *fstartptr; /* start of its data area */
  114. char *fendptr; /* end+1 of its data area */
  115. /* Some operations on the expanded record need a short-lived context */
  116. MemoryContext er_short_term_cxt; /* short-term memory context */
  117. /* Working state for domain checking, used if ER_FLAG_IS_DOMAIN is set */
  118. struct ExpandedRecordHeader *er_dummy_header; /* dummy record header */
  119. void *er_domaininfo; /* cache space for domain_check() */
  120. /* Callback info (it's active if er_mcb.arg is not NULL) */
  121. MemoryContextCallback er_mcb;
  122. } ExpandedRecordHeader;
  123. /* fmgr macros for expanded record objects */
  124. #define PG_GETARG_EXPANDED_RECORD(n) DatumGetExpandedRecord(PG_GETARG_DATUM(n))
  125. #define ExpandedRecordGetDatum(erh) EOHPGetRWDatum(&(erh)->hdr)
  126. #define ExpandedRecordGetRODatum(erh) EOHPGetRODatum(&(erh)->hdr)
  127. #define PG_RETURN_EXPANDED_RECORD(x) PG_RETURN_DATUM(ExpandedRecordGetDatum(x))
  128. /* assorted other macros */
  129. #define ExpandedRecordIsEmpty(erh) \
  130. (((erh)->flags & (ER_FLAG_DVALUES_VALID | ER_FLAG_FVALUE_VALID)) == 0)
  131. #define ExpandedRecordIsDomain(erh) \
  132. (((erh)->flags & ER_FLAG_IS_DOMAIN) != 0)
  133. /* this can substitute for TransferExpandedObject() when we already have erh */
  134. #define TransferExpandedRecord(erh, cxt) \
  135. MemoryContextSetParent((erh)->hdr.eoh_context, cxt)
  136. /* information returned by expanded_record_lookup_field() */
  137. typedef struct ExpandedRecordFieldInfo
  138. {
  139. int fnumber; /* field's attr number in record */
  140. Oid ftypeid; /* field's type/typmod info */
  141. int32 ftypmod;
  142. Oid fcollation; /* field's collation if any */
  143. } ExpandedRecordFieldInfo;
  144. /*
  145. * prototypes for functions defined in expandedrecord.c
  146. */
  147. extern ExpandedRecordHeader *make_expanded_record_from_typeid(Oid type_id, int32 typmod,
  148. MemoryContext parentcontext);
  149. extern ExpandedRecordHeader *make_expanded_record_from_tupdesc(TupleDesc tupdesc,
  150. MemoryContext parentcontext);
  151. extern ExpandedRecordHeader *make_expanded_record_from_exprecord(ExpandedRecordHeader *olderh,
  152. MemoryContext parentcontext);
  153. extern void expanded_record_set_tuple(ExpandedRecordHeader *erh,
  154. HeapTuple tuple, bool copy, bool expand_external);
  155. extern Datum make_expanded_record_from_datum(Datum recorddatum,
  156. MemoryContext parentcontext);
  157. extern TupleDesc expanded_record_fetch_tupdesc(ExpandedRecordHeader *erh);
  158. extern HeapTuple expanded_record_get_tuple(ExpandedRecordHeader *erh);
  159. extern ExpandedRecordHeader *DatumGetExpandedRecord(Datum d);
  160. extern void deconstruct_expanded_record(ExpandedRecordHeader *erh);
  161. extern bool expanded_record_lookup_field(ExpandedRecordHeader *erh,
  162. const char *fieldname,
  163. ExpandedRecordFieldInfo *finfo);
  164. extern Datum expanded_record_fetch_field(ExpandedRecordHeader *erh, int fnumber,
  165. bool *isnull);
  166. extern void expanded_record_set_field_internal(ExpandedRecordHeader *erh,
  167. int fnumber,
  168. Datum newValue, bool isnull,
  169. bool expand_external,
  170. bool check_constraints);
  171. extern void expanded_record_set_fields(ExpandedRecordHeader *erh,
  172. const Datum *newValues, const bool *isnulls,
  173. bool expand_external);
  174. /* outside code should never call expanded_record_set_field_internal as such */
  175. #define expanded_record_set_field(erh, fnumber, newValue, isnull, expand_external) \
  176. expanded_record_set_field_internal(erh, fnumber, newValue, isnull, expand_external, true)
  177. /*
  178. * Inline-able fast cases. The expanded_record_fetch_xxx functions above
  179. * handle the general cases.
  180. */
  181. /* Get the tupdesc for the expanded record's actual type */
  182. static inline TupleDesc
  183. expanded_record_get_tupdesc(ExpandedRecordHeader *erh)
  184. {
  185. if (likely(erh->er_tupdesc != NULL))
  186. return erh->er_tupdesc;
  187. else
  188. return expanded_record_fetch_tupdesc(erh);
  189. }
  190. /* Get value of record field */
  191. static inline Datum
  192. expanded_record_get_field(ExpandedRecordHeader *erh, int fnumber,
  193. bool *isnull)
  194. {
  195. if ((erh->flags & ER_FLAG_DVALUES_VALID) &&
  196. likely(fnumber > 0 && fnumber <= erh->nfields))
  197. {
  198. *isnull = erh->dnulls[fnumber - 1];
  199. return erh->dvalues[fnumber - 1];
  200. }
  201. else
  202. return expanded_record_fetch_field(erh, fnumber, isnull);
  203. }
  204. #endif /* EXPANDEDRECORD_H */