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-2026, 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
33 569364 : ginarrayextract(PG_FUNCTION_ARGS)
34 : {
35 : /* Make copy of array input to ensure it doesn't disappear while in use */
36 569364 : ArrayType *array = PG_GETARG_ARRAYTYPE_P_COPY(0);
37 569364 : int32 *nkeys = (int32 *) PG_GETARG_POINTER(1);
38 569364 : 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 :
46 569364 : get_typlenbyvalalign(ARR_ELEMTYPE(array),
47 : &elmlen, &elmbyval, &elmalign);
48 :
49 569364 : deconstruct_array(array,
50 : ARR_ELEMTYPE(array),
51 : elmlen, elmbyval, elmalign,
52 : &elems, &nulls, &nelems);
53 :
54 569364 : *nkeys = nelems;
55 569364 : *nullFlags = nulls;
56 :
57 : /* we should not free array, elems[i] points into it */
58 569364 : 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
68 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
79 666 : ginqueryarrayextract(PG_FUNCTION_ARGS)
80 : {
81 : /* Make copy of array input to ensure it doesn't disappear while in use */
82 666 : ArrayType *array = PG_GETARG_ARRAYTYPE_P_COPY(0);
83 666 : int32 *nkeys = (int32 *) PG_GETARG_POINTER(1);
84 666 : StrategyNumber strategy = PG_GETARG_UINT16(2);
85 : #ifdef NOT_USED
86 : bool **pmatch = (bool **) PG_GETARG_POINTER(3);
87 : Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4);
88 : #endif
89 666 : bool **nullFlags = (bool **) PG_GETARG_POINTER(5);
90 666 : int32 *searchMode = (int32 *) PG_GETARG_POINTER(6);
91 : int16 elmlen;
92 : bool elmbyval;
93 : char elmalign;
94 : Datum *elems;
95 : bool *nulls;
96 : int nelems;
97 :
98 666 : get_typlenbyvalalign(ARR_ELEMTYPE(array),
99 : &elmlen, &elmbyval, &elmalign);
100 :
101 666 : deconstruct_array(array,
102 : ARR_ELEMTYPE(array),
103 : elmlen, elmbyval, elmalign,
104 : &elems, &nulls, &nelems);
105 :
106 666 : *nkeys = nelems;
107 666 : *nullFlags = nulls;
108 :
109 666 : switch (strategy)
110 : {
111 82 : case GinOverlapStrategy:
112 82 : *searchMode = GIN_SEARCH_MODE_DEFAULT;
113 82 : break;
114 530 : case GinContainsStrategy:
115 530 : if (nelems > 0)
116 338 : *searchMode = GIN_SEARCH_MODE_DEFAULT;
117 : else /* everything contains the empty set */
118 192 : *searchMode = GIN_SEARCH_MODE_ALL;
119 530 : break;
120 24 : case GinContainedStrategy:
121 : /* empty set is contained in everything */
122 24 : *searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY;
123 24 : break;
124 30 : case GinEqualStrategy:
125 30 : if (nelems > 0)
126 12 : *searchMode = GIN_SEARCH_MODE_DEFAULT;
127 : else
128 18 : *searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY;
129 30 : break;
130 0 : default:
131 0 : elog(ERROR, "ginqueryarrayextract: unknown strategy number: %d",
132 : strategy);
133 : }
134 :
135 : /* we should not free array, elems[i] points into it */
136 666 : PG_RETURN_POINTER(elems);
137 : }
138 :
139 : /*
140 : * consistent support function
141 : */
142 : Datum
143 405 : ginarrayconsistent(PG_FUNCTION_ARGS)
144 : {
145 405 : bool *check = (bool *) PG_GETARG_POINTER(0);
146 405 : StrategyNumber strategy = PG_GETARG_UINT16(1);
147 : #ifdef NOT_USED
148 : ArrayType *query = PG_GETARG_ARRAYTYPE_P(2);
149 : #endif
150 405 : int32 nkeys = PG_GETARG_INT32(3);
151 : #ifdef NOT_USED
152 : Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4);
153 : #endif
154 405 : bool *recheck = (bool *) PG_GETARG_POINTER(5);
155 : #ifdef NOT_USED
156 : Datum *queryKeys = (Datum *) PG_GETARG_POINTER(6);
157 : #endif
158 405 : bool *nullFlags = (bool *) PG_GETARG_POINTER(7);
159 : bool res;
160 : int32 i;
161 :
162 405 : switch (strategy)
163 : {
164 0 : case GinOverlapStrategy:
165 : /* result is not lossy */
166 0 : *recheck = false;
167 : /* must have a match for at least one non-null element */
168 0 : res = false;
169 0 : for (i = 0; i < nkeys; i++)
170 : {
171 0 : if (check[i] && !nullFlags[i])
172 : {
173 0 : res = true;
174 0 : break;
175 : }
176 : }
177 0 : break;
178 405 : case GinContainsStrategy:
179 : /* result is not lossy */
180 405 : *recheck = false;
181 : /* must have all elements in check[] true, and no nulls */
182 405 : res = true;
183 555 : for (i = 0; i < nkeys; i++)
184 : {
185 150 : if (!check[i] || nullFlags[i])
186 : {
187 0 : res = false;
188 0 : break;
189 : }
190 : }
191 405 : break;
192 0 : case GinContainedStrategy:
193 : /* we will need recheck */
194 0 : *recheck = true;
195 : /* can't do anything else useful here */
196 0 : res = true;
197 0 : break;
198 0 : case GinEqualStrategy:
199 : /* we will need recheck */
200 0 : *recheck = true;
201 :
202 : /*
203 : * Must have all elements in check[] true; no discrimination
204 : * against nulls here. This is because array_contain_compare and
205 : * array_eq handle nulls differently ...
206 : */
207 0 : res = true;
208 0 : for (i = 0; i < nkeys; i++)
209 : {
210 0 : if (!check[i])
211 : {
212 0 : res = false;
213 0 : break;
214 : }
215 : }
216 0 : break;
217 0 : default:
218 0 : elog(ERROR, "ginarrayconsistent: unknown strategy number: %d",
219 : strategy);
220 : res = false;
221 : }
222 :
223 405 : PG_RETURN_BOOL(res);
224 : }
225 :
226 : /*
227 : * triconsistent support function
228 : */
229 : Datum
230 404295 : ginarraytriconsistent(PG_FUNCTION_ARGS)
231 : {
232 404295 : GinTernaryValue *check = (GinTernaryValue *) PG_GETARG_POINTER(0);
233 404295 : StrategyNumber strategy = PG_GETARG_UINT16(1);
234 : #ifdef NOT_USED
235 : ArrayType *query = PG_GETARG_ARRAYTYPE_P(2);
236 : #endif
237 404295 : int32 nkeys = PG_GETARG_INT32(3);
238 : #ifdef NOT_USED
239 : Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4);
240 : Datum *queryKeys = (Datum *) PG_GETARG_POINTER(5);
241 : #endif
242 404295 : bool *nullFlags = (bool *) PG_GETARG_POINTER(6);
243 : GinTernaryValue res;
244 : int32 i;
245 :
246 404295 : switch (strategy)
247 : {
248 1746 : case GinOverlapStrategy:
249 : /* must have a match for at least one non-null element */
250 1746 : res = GIN_FALSE;
251 461067 : for (i = 0; i < nkeys; i++)
252 : {
253 459566 : if (!nullFlags[i])
254 : {
255 459566 : if (check[i] == GIN_TRUE)
256 : {
257 245 : res = GIN_TRUE;
258 245 : break;
259 : }
260 459321 : else if (check[i] == GIN_MAYBE && res == GIN_FALSE)
261 : {
262 1501 : res = GIN_MAYBE;
263 : }
264 : }
265 : }
266 1746 : break;
267 402345 : case GinContainsStrategy:
268 : /* must have all elements in check[] true, and no nulls */
269 402345 : res = GIN_TRUE;
270 744060 : for (i = 0; i < nkeys; i++)
271 : {
272 341739 : if (check[i] == GIN_FALSE || nullFlags[i])
273 : {
274 24 : res = GIN_FALSE;
275 24 : break;
276 : }
277 341715 : if (check[i] == GIN_MAYBE)
278 : {
279 6 : res = GIN_MAYBE;
280 : }
281 : }
282 402345 : break;
283 168 : case GinContainedStrategy:
284 : /* can't do anything else useful here */
285 168 : res = GIN_MAYBE;
286 168 : break;
287 36 : case GinEqualStrategy:
288 :
289 : /*
290 : * Must have all elements in check[] true; no discrimination
291 : * against nulls here. This is because array_contain_compare and
292 : * array_eq handle nulls differently ...
293 : */
294 36 : res = GIN_MAYBE;
295 66 : for (i = 0; i < nkeys; i++)
296 : {
297 51 : if (check[i] == GIN_FALSE)
298 : {
299 21 : res = GIN_FALSE;
300 21 : break;
301 : }
302 : }
303 36 : break;
304 0 : default:
305 0 : elog(ERROR, "ginarrayconsistent: unknown strategy number: %d",
306 : strategy);
307 : res = false;
308 : }
309 :
310 404295 : PG_RETURN_GIN_TERNARY_VALUE(res);
311 : }
|