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
array_iter_setup(array_iter * it,AnyArrayType * a)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
array_iter_next(array_iter * it,bool * isnull,int i,int elmlen,bool elmbyval,char elmalign)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