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-2017, 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 /* Size of an EXTERNAL datum that contains a pointer to an expanded object */
48 #define EXPANDED_POINTER_SIZE (VARHDRSZ_EXTERNAL + sizeof(varatt_expanded))
49 
50 /*
51  * "Methods" that must be provided for any expanded object.
52  *
53  * get_flat_size: compute space needed for flattened representation (total,
54  * including header).
55  *
56  * flatten_into: construct flattened representation in the caller-allocated
57  * space at *result, of size allocated_size (which will always be the result
58  * of a preceding get_flat_size call; it's passed for cross-checking).
59  *
60  * The flattened representation must be a valid in-line, non-compressed,
61  * 4-byte-header varlena object.
62  *
63  * Note: construction of a heap tuple from an expanded datum calls
64  * get_flat_size twice, so it's worthwhile to make sure that that doesn't
65  * incur too much overhead.
66  */
67 typedef Size (*EOM_get_flat_size_method) (ExpandedObjectHeader *eohptr);
68 typedef void (*EOM_flatten_into_method) (ExpandedObjectHeader *eohptr,
69 										 void *result, Size allocated_size);
70 
71 /* Struct of function pointers for an expanded object's methods */
72 typedef struct ExpandedObjectMethods
73 {
74 	EOM_get_flat_size_method get_flat_size;
75 	EOM_flatten_into_method flatten_into;
76 } ExpandedObjectMethods;
77 
78 /*
79  * Every expanded object must contain this header; typically the header
80  * is embedded in some larger struct that adds type-specific fields.
81  *
82  * It is presumed that the header object and all subsidiary data are stored
83  * in eoh_context, so that the object can be freed by deleting that context,
84  * or its storage lifespan can be altered by reparenting the context.
85  * (In principle the object could own additional resources, such as malloc'd
86  * storage, and use a memory context reset callback to free them upon reset or
87  * deletion of eoh_context.)
88  *
89  * We set up two TOAST pointers within the standard header, one read-write
90  * and one read-only.  This allows functions to return either kind of pointer
91  * without making an additional allocation, and in particular without worrying
92  * whether a separately palloc'd object would have sufficient lifespan.
93  * But note that these pointers are just a convenience; a pointer object
94  * appearing somewhere else would still be legal.
95  *
96  * The typedef declaration for this appears in postgres.h.
97  */
98 struct ExpandedObjectHeader
99 {
100 	/* Phony varlena header */
101 	int32		vl_len_;		/* always EOH_HEADER_MAGIC, see below */
102 
103 	/* Pointer to methods required for object type */
104 	const ExpandedObjectMethods *eoh_methods;
105 
106 	/* Memory context containing this header and subsidiary data */
107 	MemoryContext eoh_context;
108 
109 	/* Standard R/W TOAST pointer for this object is kept here */
110 	char		eoh_rw_ptr[EXPANDED_POINTER_SIZE];
111 
112 	/* Standard R/O TOAST pointer for this object is kept here */
113 	char		eoh_ro_ptr[EXPANDED_POINTER_SIZE];
114 };
115 
116 /*
117  * Particularly for read-only functions, it is handy to be able to work with
118  * either regular "flat" varlena inputs or expanded inputs of the same data
119  * type.  To allow determining which case an argument-fetching function has
120  * returned, the first int32 of an ExpandedObjectHeader always contains -1
121  * (EOH_HEADER_MAGIC to the code).  This works since no 4-byte-header varlena
122  * could have that as its first 4 bytes.  Caution: we could not reliably tell
123  * the difference between an ExpandedObjectHeader and a short-header object
124  * with this trick.  However, it works fine if the argument fetching code
125  * always returns either a 4-byte-header flat object or an expanded object.
126  */
127 #define EOH_HEADER_MAGIC (-1)
128 #define VARATT_IS_EXPANDED_HEADER(PTR) \
129 	(((varattrib_4b *) (PTR))->va_4byte.va_header == EOH_HEADER_MAGIC)
130 
131 /*
132  * Generic support functions for expanded objects.
133  * (More of these might be worth inlining later.)
134  */
135 
136 #define EOHPGetRWDatum(eohptr)	PointerGetDatum((eohptr)->eoh_rw_ptr)
137 #define EOHPGetRODatum(eohptr)	PointerGetDatum((eohptr)->eoh_ro_ptr)
138 
139 /* Does the Datum represent a writable expanded object? */
140 #define DatumIsReadWriteExpandedObject(d, isnull, typlen) \
141 	(((isnull) || (typlen) != -1) ? false : \
142 	 VARATT_IS_EXTERNAL_EXPANDED_RW(DatumGetPointer(d)))
143 
144 #define MakeExpandedObjectReadOnly(d, isnull, typlen) \
145 	(((isnull) || (typlen) != -1) ? (d) : \
146 	 MakeExpandedObjectReadOnlyInternal(d))
147 
148 extern ExpandedObjectHeader *DatumGetEOHP(Datum d);
149 extern void EOH_init_header(ExpandedObjectHeader *eohptr,
150 				const ExpandedObjectMethods *methods,
151 				MemoryContext obj_context);
152 extern Size EOH_get_flat_size(ExpandedObjectHeader *eohptr);
153 extern void EOH_flatten_into(ExpandedObjectHeader *eohptr,
154 				 void *result, Size allocated_size);
155 extern Datum MakeExpandedObjectReadOnlyInternal(Datum d);
156 extern Datum TransferExpandedObject(Datum d, MemoryContext new_parent);
157 extern void DeleteExpandedObject(Datum d);
158 
159 #endif							/* EXPANDEDDATUM_H */
160