1 | /*------------------------------------------------------------------------- |
2 | * |
3 | * array.h |
4 | * Declarations for Postgres arrays. |
5 | * |
6 | * A standard varlena array has the following internal structure: |
7 | * <vl_len_> - standard varlena header word |
8 | * <ndim> - number of dimensions of the array |
9 | * <dataoffset> - offset to stored data, or 0 if no nulls bitmap |
10 | * <elemtype> - element type OID |
11 | * <dimensions> - length of each array axis (C array of int) |
12 | * <lower bnds> - lower boundary of each dimension (C array of int) |
13 | * <null bitmap> - bitmap showing locations of nulls (OPTIONAL) |
14 | * <actual data> - whatever is the stored data |
15 | * |
16 | * The <dimensions> and <lower bnds> arrays each have ndim elements. |
17 | * |
18 | * The <null bitmap> may be omitted if the array contains no NULL elements. |
19 | * If it is absent, the <dataoffset> field is zero and the offset to the |
20 | * stored data must be computed on-the-fly. If the bitmap is present, |
21 | * <dataoffset> is nonzero and is equal to the offset from the array start |
22 | * to the first data element (including any alignment padding). The bitmap |
23 | * follows the same conventions as tuple null bitmaps, ie, a 1 indicates |
24 | * a non-null entry and the LSB of each bitmap byte is used first. |
25 | * |
26 | * The actual data starts on a MAXALIGN boundary. Individual items in the |
27 | * array are aligned as specified by the array element type. They are |
28 | * stored in row-major order (last subscript varies most rapidly). |
29 | * |
30 | * NOTE: it is important that array elements of toastable datatypes NOT be |
31 | * toasted, since the tupletoaster won't know they are there. (We could |
32 | * support compressed toasted items; only out-of-line items are dangerous. |
33 | * However, it seems preferable to store such items uncompressed and allow |
34 | * the toaster to compress the whole array as one input.) |
35 | * |
36 | * |
37 | * The OIDVECTOR and INT2VECTOR datatypes are storage-compatible with |
38 | * generic arrays, but they support only one-dimensional arrays with no |
39 | * nulls (and no null bitmap). They don't support being toasted, either. |
40 | * |
41 | * There are also some "fixed-length array" datatypes, such as NAME and |
42 | * POINT. These are simply a sequence of a fixed number of items each |
43 | * of a fixed-length datatype, with no overhead; the item size must be |
44 | * a multiple of its alignment requirement, because we do no padding. |
45 | * We support subscripting on these types, but array_in() and array_out() |
46 | * only work with varlena arrays. |
47 | * |
48 | * In addition, arrays are a major user of the "expanded object" TOAST |
49 | * infrastructure. This allows a varlena array to be converted to a |
50 | * separate representation that may include "deconstructed" Datum/isnull |
51 | * arrays holding the elements. |
52 | * |
53 | * |
54 | * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group |
55 | * Portions Copyright (c) 1994, Regents of the University of California |
56 | * |
57 | * src/include/utils/array.h |
58 | * |
59 | *------------------------------------------------------------------------- |
60 | */ |
61 | #ifndef ARRAY_H |
62 | #define ARRAY_H |
63 | |
64 | #include "fmgr.h" |
65 | #include "utils/expandeddatum.h" |
66 | |
67 | /* avoid including execnodes.h here */ |
68 | struct ExprState; |
69 | struct ExprContext; |
70 | |
71 | |
72 | /* |
73 | * Arrays are varlena objects, so must meet the varlena convention that |
74 | * the first int32 of the object contains the total object size in bytes. |
75 | * Be sure to use VARSIZE() and SET_VARSIZE() to access it, though! |
76 | * |
77 | * CAUTION: if you change the header for ordinary arrays you will also |
78 | * need to change the headers for oidvector and int2vector! |
79 | */ |
80 | typedef struct |
81 | { |
82 | int32 vl_len_; /* varlena header (do not touch directly!) */ |
83 | int ndim; /* # of dimensions */ |
84 | int32 dataoffset; /* offset to data, or 0 if no bitmap */ |
85 | Oid elemtype; /* element type OID */ |
86 | } ArrayType; |
87 | |
88 | /* |
89 | * An expanded array is contained within a private memory context (as |
90 | * all expanded objects must be) and has a control structure as below. |
91 | * |
92 | * The expanded array might contain a regular "flat" array if that was the |
93 | * original input and we've not modified it significantly. Otherwise, the |
94 | * contents are represented by Datum/isnull arrays plus dimensionality and |
95 | * type information. We could also have both forms, if we've deconstructed |
96 | * the original array for access purposes but not yet changed it. For pass- |
97 | * by-reference element types, the Datums would point into the flat array in |
98 | * this situation. Once we start modifying array elements, new pass-by-ref |
99 | * elements are separately palloc'd within the memory context. |
100 | */ |
101 | #define EA_MAGIC 689375833 /* ID for debugging crosschecks */ |
102 | |
103 | typedef struct ExpandedArrayHeader |
104 | { |
105 | /* Standard header for expanded objects */ |
106 | ExpandedObjectHeader hdr; |
107 | |
108 | /* Magic value identifying an expanded array (for debugging only) */ |
109 | int ea_magic; |
110 | |
111 | /* Dimensionality info (always valid) */ |
112 | int ndims; /* # of dimensions */ |
113 | int *dims; /* array dimensions */ |
114 | int *lbound; /* index lower bounds for each dimension */ |
115 | |
116 | /* Element type info (always valid) */ |
117 | Oid element_type; /* element type OID */ |
118 | int16 typlen; /* needed info about element datatype */ |
119 | bool typbyval; |
120 | char typalign; |
121 | |
122 | /* |
123 | * If we have a Datum-array representation of the array, it's kept here; |
124 | * else dvalues/dnulls are NULL. The dvalues and dnulls arrays are always |
125 | * palloc'd within the object private context, but may change size from |
126 | * time to time. For pass-by-ref element types, dvalues entries might |
127 | * point either into the fstartptr..fendptr area, or to separately |
128 | * palloc'd chunks. Elements should always be fully detoasted, as they |
129 | * are in the standard flat representation. |
130 | * |
131 | * Even when dvalues is valid, dnulls can be NULL if there are no null |
132 | * elements. |
133 | */ |
134 | Datum *dvalues; /* array of Datums */ |
135 | bool *dnulls; /* array of is-null flags for Datums */ |
136 | int dvalueslen; /* allocated length of above arrays */ |
137 | int nelems; /* number of valid entries in above arrays */ |
138 | |
139 | /* |
140 | * flat_size is the current space requirement for the flat equivalent of |
141 | * the expanded array, if known; otherwise it's 0. We store this to make |
142 | * consecutive calls of get_flat_size cheap. |
143 | */ |
144 | Size flat_size; |
145 | |
146 | /* |
147 | * fvalue points to the flat representation if it is valid, else it is |
148 | * NULL. If we have or ever had a flat representation then |
149 | * fstartptr/fendptr point to the start and end+1 of its data area; this |
150 | * is so that we can tell which Datum pointers point into the flat |
151 | * representation rather than being pointers to separately palloc'd data. |
152 | */ |
153 | ArrayType *fvalue; /* must be a fully detoasted array */ |
154 | char *fstartptr; /* start of its data area */ |
155 | char *fendptr; /* end+1 of its data area */ |
156 | } ExpandedArrayHeader; |
157 | |
158 | /* |
159 | * Functions that can handle either a "flat" varlena array or an expanded |
160 | * array use this union to work with their input. Don't refer to "flt"; |
161 | * instead, cast to ArrayType. This struct nominally requires 8-byte |
162 | * alignment on 64-bit, but it's often used for an ArrayType having 4-byte |
163 | * alignment. UBSan complains about referencing "flt" in such cases. |
164 | */ |
165 | typedef union AnyArrayType |
166 | { |
167 | ArrayType flt; |
168 | ExpandedArrayHeader xpn; |
169 | } AnyArrayType; |
170 | |
171 | /* |
172 | * working state for accumArrayResult() and friends |
173 | * note that the input must be scalars (legal array elements) |
174 | */ |
175 | typedef struct ArrayBuildState |
176 | { |
177 | MemoryContext mcontext; /* where all the temp stuff is kept */ |
178 | Datum *dvalues; /* array of accumulated Datums */ |
179 | bool *dnulls; /* array of is-null flags for Datums */ |
180 | int alen; /* allocated length of above arrays */ |
181 | int nelems; /* number of valid entries in above arrays */ |
182 | Oid element_type; /* data type of the Datums */ |
183 | int16 typlen; /* needed info about datatype */ |
184 | bool typbyval; |
185 | char typalign; |
186 | bool private_cxt; /* use private memory context */ |
187 | } ArrayBuildState; |
188 | |
189 | /* |
190 | * working state for accumArrayResultArr() and friends |
191 | * note that the input must be arrays, and the same array type is returned |
192 | */ |
193 | typedef struct ArrayBuildStateArr |
194 | { |
195 | MemoryContext mcontext; /* where all the temp stuff is kept */ |
196 | char *data; /* accumulated data */ |
197 | bits8 *nullbitmap; /* bitmap of is-null flags, or NULL if none */ |
198 | int abytes; /* allocated length of "data" */ |
199 | int nbytes; /* number of bytes used so far */ |
200 | int aitems; /* allocated length of bitmap (in elements) */ |
201 | int nitems; /* total number of elements in result */ |
202 | int ndims; /* current dimensions of result */ |
203 | int dims[MAXDIM]; |
204 | int lbs[MAXDIM]; |
205 | Oid array_type; /* data type of the arrays */ |
206 | Oid element_type; /* data type of the array elements */ |
207 | bool private_cxt; /* use private memory context */ |
208 | } ArrayBuildStateArr; |
209 | |
210 | /* |
211 | * working state for accumArrayResultAny() and friends |
212 | * these functions handle both cases |
213 | */ |
214 | typedef struct ArrayBuildStateAny |
215 | { |
216 | /* Exactly one of these is not NULL: */ |
217 | ArrayBuildState *scalarstate; |
218 | ArrayBuildStateArr *arraystate; |
219 | } ArrayBuildStateAny; |
220 | |
221 | /* |
222 | * structure to cache type metadata needed for array manipulation |
223 | */ |
224 | typedef struct ArrayMetaState |
225 | { |
226 | Oid element_type; |
227 | int16 typlen; |
228 | bool typbyval; |
229 | char typalign; |
230 | char typdelim; |
231 | Oid typioparam; |
232 | Oid typiofunc; |
233 | FmgrInfo proc; |
234 | } ArrayMetaState; |
235 | |
236 | /* |
237 | * private state needed by array_map (here because caller must provide it) |
238 | */ |
239 | typedef struct ArrayMapState |
240 | { |
241 | ArrayMetaState ; |
242 | ArrayMetaState ; |
243 | } ArrayMapState; |
244 | |
245 | /* ArrayIteratorData is private in arrayfuncs.c */ |
246 | typedef struct ArrayIteratorData *ArrayIterator; |
247 | |
248 | /* fmgr macros for regular varlena array objects */ |
249 | #define DatumGetArrayTypeP(X) ((ArrayType *) PG_DETOAST_DATUM(X)) |
250 | #define DatumGetArrayTypePCopy(X) ((ArrayType *) PG_DETOAST_DATUM_COPY(X)) |
251 | #define PG_GETARG_ARRAYTYPE_P(n) DatumGetArrayTypeP(PG_GETARG_DATUM(n)) |
252 | #define PG_GETARG_ARRAYTYPE_P_COPY(n) DatumGetArrayTypePCopy(PG_GETARG_DATUM(n)) |
253 | #define PG_RETURN_ARRAYTYPE_P(x) PG_RETURN_POINTER(x) |
254 | |
255 | /* fmgr macros for expanded array objects */ |
256 | #define PG_GETARG_EXPANDED_ARRAY(n) DatumGetExpandedArray(PG_GETARG_DATUM(n)) |
257 | #define PG_GETARG_EXPANDED_ARRAYX(n, metacache) \ |
258 | DatumGetExpandedArrayX(PG_GETARG_DATUM(n), metacache) |
259 | #define PG_RETURN_EXPANDED_ARRAY(x) PG_RETURN_DATUM(EOHPGetRWDatum(&(x)->hdr)) |
260 | |
261 | /* fmgr macros for AnyArrayType (ie, get either varlena or expanded form) */ |
262 | #define PG_GETARG_ANY_ARRAY_P(n) DatumGetAnyArrayP(PG_GETARG_DATUM(n)) |
263 | |
264 | /* |
265 | * Access macros for varlena array header fields. |
266 | * |
267 | * ARR_DIMS returns a pointer to an array of array dimensions (number of |
268 | * elements along the various array axes). |
269 | * |
270 | * ARR_LBOUND returns a pointer to an array of array lower bounds. |
271 | * |
272 | * That is: if the third axis of an array has elements 5 through 8, then |
273 | * ARR_DIMS(a)[2] == 4 and ARR_LBOUND(a)[2] == 5. |
274 | * |
275 | * Unlike C, the default lower bound is 1. |
276 | */ |
277 | #define ARR_SIZE(a) VARSIZE(a) |
278 | #define ARR_NDIM(a) ((a)->ndim) |
279 | #define ARR_HASNULL(a) ((a)->dataoffset != 0) |
280 | #define ARR_ELEMTYPE(a) ((a)->elemtype) |
281 | |
282 | #define ARR_DIMS(a) \ |
283 | ((int *) (((char *) (a)) + sizeof(ArrayType))) |
284 | #define ARR_LBOUND(a) \ |
285 | ((int *) (((char *) (a)) + sizeof(ArrayType) + \ |
286 | sizeof(int) * ARR_NDIM(a))) |
287 | |
288 | #define ARR_NULLBITMAP(a) \ |
289 | (ARR_HASNULL(a) ? \ |
290 | (bits8 *) (((char *) (a)) + sizeof(ArrayType) + \ |
291 | 2 * sizeof(int) * ARR_NDIM(a)) \ |
292 | : (bits8 *) NULL) |
293 | |
294 | /* |
295 | * The total array header size (in bytes) for an array with the specified |
296 | * number of dimensions and total number of items. |
297 | */ |
298 | #define ARR_OVERHEAD_NONULLS(ndims) \ |
299 | MAXALIGN(sizeof(ArrayType) + 2 * sizeof(int) * (ndims)) |
300 | #define ARR_OVERHEAD_WITHNULLS(ndims, nitems) \ |
301 | MAXALIGN(sizeof(ArrayType) + 2 * sizeof(int) * (ndims) + \ |
302 | ((nitems) + 7) / 8) |
303 | |
304 | #define ARR_DATA_OFFSET(a) \ |
305 | (ARR_HASNULL(a) ? (a)->dataoffset : ARR_OVERHEAD_NONULLS(ARR_NDIM(a))) |
306 | |
307 | /* |
308 | * Returns a pointer to the actual array data. |
309 | */ |
310 | #define ARR_DATA_PTR(a) \ |
311 | (((char *) (a)) + ARR_DATA_OFFSET(a)) |
312 | |
313 | /* |
314 | * Macros for working with AnyArrayType inputs. Beware multiple references! |
315 | */ |
316 | #define AARR_NDIM(a) \ |
317 | (VARATT_IS_EXPANDED_HEADER(a) ? \ |
318 | (a)->xpn.ndims : ARR_NDIM((ArrayType *) (a))) |
319 | #define AARR_HASNULL(a) \ |
320 | (VARATT_IS_EXPANDED_HEADER(a) ? \ |
321 | ((a)->xpn.dvalues != NULL ? (a)->xpn.dnulls != NULL : ARR_HASNULL((a)->xpn.fvalue)) : \ |
322 | ARR_HASNULL((ArrayType *) (a))) |
323 | #define AARR_ELEMTYPE(a) \ |
324 | (VARATT_IS_EXPANDED_HEADER(a) ? \ |
325 | (a)->xpn.element_type : ARR_ELEMTYPE((ArrayType *) (a))) |
326 | #define AARR_DIMS(a) \ |
327 | (VARATT_IS_EXPANDED_HEADER(a) ? \ |
328 | (a)->xpn.dims : ARR_DIMS((ArrayType *) (a))) |
329 | #define AARR_LBOUND(a) \ |
330 | (VARATT_IS_EXPANDED_HEADER(a) ? \ |
331 | (a)->xpn.lbound : ARR_LBOUND((ArrayType *) (a))) |
332 | |
333 | |
334 | /* |
335 | * GUC parameter |
336 | */ |
337 | extern bool Array_nulls; |
338 | |
339 | /* |
340 | * prototypes for functions defined in arrayfuncs.c |
341 | */ |
342 | extern void CopyArrayEls(ArrayType *array, |
343 | Datum *values, |
344 | bool *nulls, |
345 | int nitems, |
346 | int typlen, |
347 | bool typbyval, |
348 | char typalign, |
349 | bool freedata); |
350 | |
351 | extern Datum array_get_element(Datum arraydatum, int nSubscripts, int *indx, |
352 | int arraytyplen, int elmlen, bool elmbyval, char elmalign, |
353 | bool *isNull); |
354 | extern Datum array_set_element(Datum arraydatum, int nSubscripts, int *indx, |
355 | Datum dataValue, bool isNull, |
356 | int arraytyplen, int elmlen, bool elmbyval, char elmalign); |
357 | extern Datum array_get_slice(Datum arraydatum, int nSubscripts, |
358 | int *upperIndx, int *lowerIndx, |
359 | bool *upperProvided, bool *lowerProvided, |
360 | int arraytyplen, int elmlen, bool elmbyval, char elmalign); |
361 | extern Datum array_set_slice(Datum arraydatum, int nSubscripts, |
362 | int *upperIndx, int *lowerIndx, |
363 | bool *upperProvided, bool *lowerProvided, |
364 | Datum srcArrayDatum, bool isNull, |
365 | int arraytyplen, int elmlen, bool elmbyval, char elmalign); |
366 | |
367 | extern Datum array_ref(ArrayType *array, int nSubscripts, int *indx, |
368 | int arraytyplen, int elmlen, bool elmbyval, char elmalign, |
369 | bool *isNull); |
370 | extern ArrayType *array_set(ArrayType *array, int nSubscripts, int *indx, |
371 | Datum dataValue, bool isNull, |
372 | int arraytyplen, int elmlen, bool elmbyval, char elmalign); |
373 | |
374 | extern Datum array_map(Datum arrayd, |
375 | struct ExprState *exprstate, struct ExprContext *econtext, |
376 | Oid retType, ArrayMapState *amstate); |
377 | |
378 | extern void array_bitmap_copy(bits8 *destbitmap, int destoffset, |
379 | const bits8 *srcbitmap, int srcoffset, |
380 | int nitems); |
381 | |
382 | extern ArrayType *construct_array(Datum *elems, int nelems, |
383 | Oid elmtype, |
384 | int elmlen, bool elmbyval, char elmalign); |
385 | extern ArrayType *construct_md_array(Datum *elems, |
386 | bool *nulls, |
387 | int ndims, |
388 | int *dims, |
389 | int *lbs, |
390 | Oid elmtype, int elmlen, bool elmbyval, char elmalign); |
391 | extern ArrayType *construct_empty_array(Oid elmtype); |
392 | extern ExpandedArrayHeader *construct_empty_expanded_array(Oid element_type, |
393 | MemoryContext parentcontext, |
394 | ArrayMetaState *metacache); |
395 | extern void deconstruct_array(ArrayType *array, |
396 | Oid elmtype, |
397 | int elmlen, bool elmbyval, char elmalign, |
398 | Datum **elemsp, bool **nullsp, int *nelemsp); |
399 | extern bool array_contains_nulls(ArrayType *array); |
400 | |
401 | extern ArrayBuildState *initArrayResult(Oid element_type, |
402 | MemoryContext rcontext, bool subcontext); |
403 | extern ArrayBuildState *accumArrayResult(ArrayBuildState *astate, |
404 | Datum dvalue, bool disnull, |
405 | Oid element_type, |
406 | MemoryContext rcontext); |
407 | extern Datum makeArrayResult(ArrayBuildState *astate, |
408 | MemoryContext rcontext); |
409 | extern Datum makeMdArrayResult(ArrayBuildState *astate, int ndims, |
410 | int *dims, int *lbs, MemoryContext rcontext, bool release); |
411 | |
412 | extern ArrayBuildStateArr *initArrayResultArr(Oid array_type, Oid element_type, |
413 | MemoryContext rcontext, bool subcontext); |
414 | extern ArrayBuildStateArr *accumArrayResultArr(ArrayBuildStateArr *astate, |
415 | Datum dvalue, bool disnull, |
416 | Oid array_type, |
417 | MemoryContext rcontext); |
418 | extern Datum makeArrayResultArr(ArrayBuildStateArr *astate, |
419 | MemoryContext rcontext, bool release); |
420 | |
421 | extern ArrayBuildStateAny *initArrayResultAny(Oid input_type, |
422 | MemoryContext rcontext, bool subcontext); |
423 | extern ArrayBuildStateAny *accumArrayResultAny(ArrayBuildStateAny *astate, |
424 | Datum dvalue, bool disnull, |
425 | Oid input_type, |
426 | MemoryContext rcontext); |
427 | extern Datum makeArrayResultAny(ArrayBuildStateAny *astate, |
428 | MemoryContext rcontext, bool release); |
429 | |
430 | extern ArrayIterator array_create_iterator(ArrayType *arr, int slice_ndim, ArrayMetaState *mstate); |
431 | extern bool array_iterate(ArrayIterator iterator, Datum *value, bool *isnull); |
432 | extern void array_free_iterator(ArrayIterator iterator); |
433 | |
434 | /* |
435 | * prototypes for functions defined in arrayutils.c |
436 | */ |
437 | |
438 | extern int ArrayGetOffset(int n, const int *dim, const int *lb, const int *indx); |
439 | extern int ArrayGetOffset0(int n, const int *tup, const int *scale); |
440 | extern int ArrayGetNItems(int ndim, const int *dims); |
441 | extern void mda_get_range(int n, int *span, const int *st, const int *endp); |
442 | extern void mda_get_prod(int n, const int *range, int *prod); |
443 | extern void mda_get_offset_values(int n, int *dist, const int *prod, const int *span); |
444 | extern int mda_next_tuple(int n, int *curr, const int *span); |
445 | extern int32 *ArrayGetIntegerTypmods(ArrayType *arr, int *n); |
446 | |
447 | /* |
448 | * prototypes for functions defined in array_expanded.c |
449 | */ |
450 | extern Datum expand_array(Datum arraydatum, MemoryContext parentcontext, |
451 | ArrayMetaState *metacache); |
452 | extern ExpandedArrayHeader *DatumGetExpandedArray(Datum d); |
453 | extern ExpandedArrayHeader *DatumGetExpandedArrayX(Datum d, |
454 | ArrayMetaState *metacache); |
455 | extern AnyArrayType *DatumGetAnyArrayP(Datum d); |
456 | extern void deconstruct_expanded_array(ExpandedArrayHeader *eah); |
457 | |
458 | #endif /* ARRAY_H */ |
459 | |