Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * ginarrayproc.c
4 : : * support functions for GIN's indexing of any array
5 : : *
6 : : *
7 : : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
8 : : * Portions Copyright (c) 1994, Regents of the University of California
9 : : *
10 : : * IDENTIFICATION
11 : : * src/backend/access/gin/ginarrayproc.c
12 : : *-------------------------------------------------------------------------
13 : : */
14 : : #include "postgres.h"
15 : :
16 : : #include "access/gin.h"
17 : : #include "access/stratnum.h"
18 : : #include "utils/array.h"
19 : : #include "utils/fmgrprotos.h"
20 : : #include "utils/lsyscache.h"
21 : :
22 : :
23 : : #define GinOverlapStrategy 1
24 : : #define GinContainsStrategy 2
25 : : #define GinContainedStrategy 3
26 : : #define GinEqualStrategy 4
27 : :
28 : :
29 : : /*
30 : : * extractValue support function
31 : : */
32 : : Datum
6912 bruce@momjian.us 33 :CBC 568443 : ginarrayextract(PG_FUNCTION_ARGS)
34 : : {
35 : : /* Make copy of array input to ensure it doesn't disappear while in use */
5356 tgl@sss.pgh.pa.us 36 : 568443 : ArrayType *array = PG_GETARG_ARRAYTYPE_P_COPY(0);
37 : 568443 : int32 *nkeys = (int32 *) PG_GETARG_POINTER(1);
38 : 568443 : bool **nullFlags = (bool **) PG_GETARG_POINTER(2);
39 : : int16 elmlen;
40 : : bool elmbyval;
41 : : char elmalign;
42 : : Datum *elems;
43 : : bool *nulls;
44 : : int nelems;
45 : :
7067 teodor@sigaev.ru 46 : 568443 : get_typlenbyvalalign(ARR_ELEMTYPE(array),
47 : : &elmlen, &elmbyval, &elmalign);
48 : :
49 : 568443 : deconstruct_array(array,
50 : : ARR_ELEMTYPE(array),
51 : : elmlen, elmbyval, elmalign,
52 : : &elems, &nulls, &nelems);
53 : :
5356 tgl@sss.pgh.pa.us 54 : 568443 : *nkeys = nelems;
55 : 568443 : *nullFlags = nulls;
56 : :
57 : : /* we should not free array, elems[i] points into it */
58 : 568443 : PG_RETURN_POINTER(elems);
59 : : }
60 : :
61 : : /*
62 : : * Formerly, ginarrayextract had only two arguments. Now it has three,
63 : : * but we still need a pg_proc entry with two args to support reloading
64 : : * pre-9.1 contrib/intarray opclass declarations. This compatibility
65 : : * function should go away eventually.
66 : : */
67 : : Datum
5316 tgl@sss.pgh.pa.us 68 :UBC 0 : ginarrayextract_2args(PG_FUNCTION_ARGS)
69 : : {
70 [ # # ]: 0 : if (PG_NARGS() < 3) /* should not happen */
71 [ # # ]: 0 : elog(ERROR, "ginarrayextract requires three arguments");
72 : 0 : return ginarrayextract(fcinfo);
73 : : }
74 : :
75 : : /*
76 : : * extractQuery support function
77 : : */
78 : : Datum
6591 tgl@sss.pgh.pa.us 79 :CBC 656 : ginqueryarrayextract(PG_FUNCTION_ARGS)
80 : : {
81 : : /* Make copy of array input to ensure it doesn't disappear while in use */
5356 82 : 656 : ArrayType *array = PG_GETARG_ARRAYTYPE_P_COPY(0);
83 : 656 : int32 *nkeys = (int32 *) PG_GETARG_POINTER(1);
84 : 656 : StrategyNumber strategy = PG_GETARG_UINT16(2);
85 : :
86 : : /* bool **pmatch = (bool **) PG_GETARG_POINTER(3); */
87 : : /* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
88 : 656 : bool **nullFlags = (bool **) PG_GETARG_POINTER(5);
89 : 656 : int32 *searchMode = (int32 *) PG_GETARG_POINTER(6);
90 : : int16 elmlen;
91 : : bool elmbyval;
92 : : char elmalign;
93 : : Datum *elems;
94 : : bool *nulls;
95 : : int nelems;
96 : :
97 : 656 : get_typlenbyvalalign(ARR_ELEMTYPE(array),
98 : : &elmlen, &elmbyval, &elmalign);
99 : :
100 : 656 : deconstruct_array(array,
101 : : ARR_ELEMTYPE(array),
102 : : elmlen, elmbyval, elmalign,
103 : : &elems, &nulls, &nelems);
104 : :
105 : 656 : *nkeys = nelems;
106 : 656 : *nullFlags = nulls;
107 : :
108 [ + + + + : 656 : switch (strategy)
- ]
109 : : {
110 : 72 : case GinOverlapStrategy:
111 : 72 : *searchMode = GIN_SEARCH_MODE_DEFAULT;
112 : 72 : break;
113 : 530 : case GinContainsStrategy:
114 [ + + ]: 530 : if (nelems > 0)
115 : 338 : *searchMode = GIN_SEARCH_MODE_DEFAULT;
116 : : else /* everything contains the empty set */
117 : 192 : *searchMode = GIN_SEARCH_MODE_ALL;
118 : 530 : break;
119 : 24 : case GinContainedStrategy:
120 : : /* empty set is contained in everything */
121 : 24 : *searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY;
122 : 24 : break;
123 : 30 : case GinEqualStrategy:
124 [ + + ]: 30 : if (nelems > 0)
125 : 12 : *searchMode = GIN_SEARCH_MODE_DEFAULT;
126 : : else
127 : 18 : *searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY;
128 : 30 : break;
5356 tgl@sss.pgh.pa.us 129 :UBC 0 : default:
130 [ # # ]: 0 : elog(ERROR, "ginqueryarrayextract: unknown strategy number: %d",
131 : : strategy);
132 : : }
133 : :
134 : : /* we should not free array, elems[i] points into it */
5356 tgl@sss.pgh.pa.us 135 :CBC 656 : PG_RETURN_POINTER(elems);
136 : : }
137 : :
138 : : /*
139 : : * consistent support function
140 : : */
141 : : Datum
6912 bruce@momjian.us 142 : 405 : ginarrayconsistent(PG_FUNCTION_ARGS)
143 : : {
144 : 405 : bool *check = (bool *) PG_GETARG_POINTER(0);
145 : 405 : StrategyNumber strategy = PG_GETARG_UINT16(1);
146 : :
147 : : /* ArrayType *query = PG_GETARG_ARRAYTYPE_P(2); */
5356 tgl@sss.pgh.pa.us 148 : 405 : int32 nkeys = PG_GETARG_INT32(3);
149 : :
150 : : /* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
6009 151 : 405 : bool *recheck = (bool *) PG_GETARG_POINTER(5);
152 : :
153 : : /* Datum *queryKeys = (Datum *) PG_GETARG_POINTER(6); */
5356 154 : 405 : bool *nullFlags = (bool *) PG_GETARG_POINTER(7);
155 : : bool res;
156 : : int32 i;
157 : :
6912 bruce@momjian.us 158 [ - + - - : 405 : switch (strategy)
- ]
159 : : {
7067 teodor@sigaev.ru 160 :UBC 0 : case GinOverlapStrategy:
161 : : /* result is not lossy */
6354 tgl@sss.pgh.pa.us 162 : 0 : *recheck = false;
163 : : /* must have a match for at least one non-null element */
5356 164 : 0 : res = false;
165 [ # # ]: 0 : for (i = 0; i < nkeys; i++)
166 : : {
167 [ # # # # ]: 0 : if (check[i] && !nullFlags[i])
168 : : {
169 : 0 : res = true;
170 : 0 : break;
171 : : }
172 : : }
7067 teodor@sigaev.ru 173 : 0 : break;
7067 teodor@sigaev.ru 174 :CBC 405 : case GinContainsStrategy:
175 : : /* result is not lossy */
6354 tgl@sss.pgh.pa.us 176 : 405 : *recheck = false;
177 : : /* must have all elements in check[] true, and no nulls */
178 : 405 : res = true;
5356 179 [ + + ]: 555 : for (i = 0; i < nkeys; i++)
180 : : {
181 [ + - - + ]: 150 : if (!check[i] || nullFlags[i])
182 : : {
6354 tgl@sss.pgh.pa.us 183 :UBC 0 : res = false;
184 : 0 : break;
185 : : }
186 : : }
6354 tgl@sss.pgh.pa.us 187 :CBC 405 : break;
5356 tgl@sss.pgh.pa.us 188 :UBC 0 : case GinContainedStrategy:
189 : : /* we will need recheck */
190 : 0 : *recheck = true;
191 : : /* can't do anything else useful here */
192 : 0 : res = true;
193 : 0 : break;
6997 teodor@sigaev.ru 194 : 0 : case GinEqualStrategy:
195 : : /* we will need recheck */
6354 tgl@sss.pgh.pa.us 196 : 0 : *recheck = true;
197 : :
198 : : /*
199 : : * Must have all elements in check[] true; no discrimination
200 : : * against nulls here. This is because array_contain_compare and
201 : : * array_eq handle nulls differently ...
202 : : */
203 : 0 : res = true;
5356 204 [ # # ]: 0 : for (i = 0; i < nkeys; i++)
205 : : {
6912 bruce@momjian.us 206 [ # # ]: 0 : if (!check[i])
207 : : {
6354 tgl@sss.pgh.pa.us 208 : 0 : res = false;
7067 teodor@sigaev.ru 209 : 0 : break;
210 : : }
211 : : }
212 : 0 : break;
213 : 0 : default:
6936 tgl@sss.pgh.pa.us 214 [ # # ]: 0 : elog(ERROR, "ginarrayconsistent: unknown strategy number: %d",
215 : : strategy);
216 : : res = false;
217 : : }
218 : :
7067 teodor@sigaev.ru 219 :CBC 405 : PG_RETURN_BOOL(res);
220 : : }
221 : :
222 : : /*
223 : : * triconsistent support function
224 : : */
225 : : Datum
4196 heikki.linnakangas@i 226 : 402611 : ginarraytriconsistent(PG_FUNCTION_ARGS)
227 : : {
4177 228 : 402611 : GinTernaryValue *check = (GinTernaryValue *) PG_GETARG_POINTER(0);
4196 229 : 402611 : StrategyNumber strategy = PG_GETARG_UINT16(1);
230 : :
231 : : /* ArrayType *query = PG_GETARG_ARRAYTYPE_P(2); */
232 : 402611 : int32 nkeys = PG_GETARG_INT32(3);
233 : :
234 : : /* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
235 : : /* Datum *queryKeys = (Datum *) PG_GETARG_POINTER(5); */
236 : 402611 : bool *nullFlags = (bool *) PG_GETARG_POINTER(6);
237 : : GinTernaryValue res;
238 : : int32 i;
239 : :
240 [ + + + + : 402611 : switch (strategy)
- ]
241 : : {
242 : 186 : case GinOverlapStrategy:
243 : : /* must have a match for at least one non-null element */
244 : 186 : res = GIN_FALSE;
245 [ + + ]: 219 : for (i = 0; i < nkeys; i++)
246 : : {
247 [ + - ]: 213 : if (!nullFlags[i])
248 : : {
249 [ + + ]: 213 : if (check[i] == GIN_TRUE)
250 : : {
251 : 180 : res = GIN_TRUE;
252 : 180 : break;
253 : : }
254 [ + + + - ]: 33 : else if (check[i] == GIN_MAYBE && res == GIN_FALSE)
255 : : {
256 : 6 : res = GIN_MAYBE;
257 : : }
258 : : }
259 : : }
260 : 186 : break;
261 : 402221 : case GinContainsStrategy:
262 : : /* must have all elements in check[] true, and no nulls */
263 : 402221 : res = GIN_TRUE;
264 [ + + ]: 743812 : for (i = 0; i < nkeys; i++)
265 : : {
266 [ + + - + ]: 341615 : if (check[i] == GIN_FALSE || nullFlags[i])
267 : : {
268 : 24 : res = GIN_FALSE;
269 : 24 : break;
270 : : }
271 [ + + ]: 341591 : if (check[i] == GIN_MAYBE)
272 : : {
273 : 6 : res = GIN_MAYBE;
274 : : }
275 : : }
276 : 402221 : break;
277 : 168 : case GinContainedStrategy:
278 : : /* can't do anything else useful here */
279 : 168 : res = GIN_MAYBE;
280 : 168 : break;
281 : 36 : case GinEqualStrategy:
282 : :
283 : : /*
284 : : * Must have all elements in check[] true; no discrimination
285 : : * against nulls here. This is because array_contain_compare and
286 : : * array_eq handle nulls differently ...
287 : : */
288 : 36 : res = GIN_MAYBE;
289 [ + + ]: 66 : for (i = 0; i < nkeys; i++)
290 : : {
291 [ + + ]: 51 : if (check[i] == GIN_FALSE)
292 : : {
293 : 21 : res = GIN_FALSE;
294 : 21 : break;
295 : : }
296 : : }
297 : 36 : break;
4196 heikki.linnakangas@i 298 :UBC 0 : default:
299 [ # # ]: 0 : elog(ERROR, "ginarrayconsistent: unknown strategy number: %d",
300 : : strategy);
301 : : res = false;
302 : : }
303 : :
4177 heikki.linnakangas@i 304 :CBC 402611 : PG_RETURN_GIN_TERNARY_VALUE(res);
305 : : }
|