1 | /*------------------------------------------------------------------------- |
2 | * |
3 | * arrayaccess.h |
4 | * Declarations for element-by-element access to Postgres arrays. |
5 | * |
6 | * |
7 | * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group |
8 | * Portions Copyright (c) 1994, Regents of the University of California |
9 | * |
10 | * src/include/utils/arrayaccess.h |
11 | * |
12 | *------------------------------------------------------------------------- |
13 | */ |
14 | #ifndef ARRAYACCESS_H |
15 | #define ARRAYACCESS_H |
16 | |
17 | #include "access/tupmacs.h" |
18 | #include "utils/array.h" |
19 | |
20 | |
21 | /* |
22 | * Functions for iterating through elements of a flat or expanded array. |
23 | * These require a state struct "array_iter iter". |
24 | * |
25 | * Use "array_iter_setup(&iter, arrayptr);" to prepare to iterate, and |
26 | * "datumvar = array_iter_next(&iter, &isnullvar, index, ...);" to fetch |
27 | * the next element into datumvar/isnullvar. |
28 | * "index" must be the zero-origin element number; we make caller provide |
29 | * this since caller is generally counting the elements anyway. Despite |
30 | * that, these functions can only fetch elements sequentially. |
31 | */ |
32 | |
33 | typedef struct array_iter |
34 | { |
35 | /* datumptr being NULL or not tells if we have flat or expanded array */ |
36 | |
37 | /* Fields used when we have an expanded array */ |
38 | Datum *datumptr; /* Pointer to Datum array */ |
39 | bool *isnullptr; /* Pointer to isnull array */ |
40 | |
41 | /* Fields used when we have a flat array */ |
42 | char *dataptr; /* Current spot in the data area */ |
43 | bits8 *bitmapptr; /* Current byte of the nulls bitmap, or NULL */ |
44 | int bitmask; /* mask for current bit in nulls bitmap */ |
45 | } array_iter; |
46 | |
47 | |
48 | static inline void |
49 | array_iter_setup(array_iter *it, AnyArrayType *a) |
50 | { |
51 | if (VARATT_IS_EXPANDED_HEADER(a)) |
52 | { |
53 | if (a->xpn.dvalues) |
54 | { |
55 | it->datumptr = a->xpn.dvalues; |
56 | it->isnullptr = a->xpn.dnulls; |
57 | /* we must fill all fields to prevent compiler warnings */ |
58 | it->dataptr = NULL; |
59 | it->bitmapptr = NULL; |
60 | } |
61 | else |
62 | { |
63 | /* Work with flat array embedded in the expanded datum */ |
64 | it->datumptr = NULL; |
65 | it->isnullptr = NULL; |
66 | it->dataptr = ARR_DATA_PTR(a->xpn.fvalue); |
67 | it->bitmapptr = ARR_NULLBITMAP(a->xpn.fvalue); |
68 | } |
69 | } |
70 | else |
71 | { |
72 | it->datumptr = NULL; |
73 | it->isnullptr = NULL; |
74 | it->dataptr = ARR_DATA_PTR((ArrayType *) a); |
75 | it->bitmapptr = ARR_NULLBITMAP((ArrayType *) a); |
76 | } |
77 | it->bitmask = 1; |
78 | } |
79 | |
80 | static inline Datum |
81 | array_iter_next(array_iter *it, bool *isnull, int i, |
82 | int elmlen, bool elmbyval, char elmalign) |
83 | { |
84 | Datum ret; |
85 | |
86 | if (it->datumptr) |
87 | { |
88 | ret = it->datumptr[i]; |
89 | *isnull = it->isnullptr ? it->isnullptr[i] : false; |
90 | } |
91 | else |
92 | { |
93 | if (it->bitmapptr && (*(it->bitmapptr) & it->bitmask) == 0) |
94 | { |
95 | *isnull = true; |
96 | ret = (Datum) 0; |
97 | } |
98 | else |
99 | { |
100 | *isnull = false; |
101 | ret = fetch_att(it->dataptr, elmbyval, elmlen); |
102 | it->dataptr = att_addlength_pointer(it->dataptr, elmlen, |
103 | it->dataptr); |
104 | it->dataptr = (char *) att_align_nominal(it->dataptr, elmalign); |
105 | } |
106 | it->bitmask <<= 1; |
107 | if (it->bitmask == 0x100) |
108 | { |
109 | if (it->bitmapptr) |
110 | it->bitmapptr++; |
111 | it->bitmask = 1; |
112 | } |
113 | } |
114 | |
115 | return ret; |
116 | } |
117 | |
118 | #endif /* ARRAYACCESS_H */ |
119 | |