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 646861 : ginarrayextract(PG_FUNCTION_ARGS)
34 : {
35 : /* Make copy of array input to ensure it doesn't disappear while in use */
36 646861 : ArrayType *array = PG_GETARG_ARRAYTYPE_P_COPY(0);
37 646861 : int32 *nkeys = (int32 *) PG_GETARG_POINTER(1);
38 646861 : 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 646861 : get_typlenbyvalalign(ARR_ELEMTYPE(array),
47 : &elmlen, &elmbyval, &elmalign);
48 :
49 646861 : deconstruct_array(array,
50 : ARR_ELEMTYPE(array),
51 : elmlen, elmbyval, elmalign,
52 : &elems, &nulls, &nelems);
53 :
54 646861 : *nkeys = nelems;
55 646861 : *nullFlags = nulls;
56 :
57 : /* we should not free array, elems[i] points into it */
58 646861 : 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 977 : ginqueryarrayextract(PG_FUNCTION_ARGS)
80 : {
81 : /* Make copy of array input to ensure it doesn't disappear while in use */
82 977 : ArrayType *array = PG_GETARG_ARRAYTYPE_P_COPY(0);
83 977 : int32 *nkeys = (int32 *) PG_GETARG_POINTER(1);
84 977 : 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 977 : bool **nullFlags = (bool **) PG_GETARG_POINTER(5);
90 977 : 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 977 : get_typlenbyvalalign(ARR_ELEMTYPE(array),
99 : &elmlen, &elmbyval, &elmalign);
100 :
101 977 : deconstruct_array(array,
102 : ARR_ELEMTYPE(array),
103 : elmlen, elmbyval, elmalign,
104 : &elems, &nulls, &nelems);
105 :
106 977 : *nkeys = nelems;
107 977 : *nullFlags = nulls;
108 :
109 977 : switch (strategy)
110 : {
111 118 : case GinOverlapStrategy:
112 118 : *searchMode = GIN_SEARCH_MODE_DEFAULT;
113 118 : break;
114 778 : case GinContainsStrategy:
115 778 : if (nelems > 0)
116 484 : *searchMode = GIN_SEARCH_MODE_DEFAULT;
117 : else /* everything contains the empty set */
118 294 : *searchMode = GIN_SEARCH_MODE_ALL;
119 778 : break;
120 36 : case GinContainedStrategy:
121 : /* empty set is contained in everything */
122 36 : *searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY;
123 36 : break;
124 45 : case GinEqualStrategy:
125 45 : if (nelems > 0)
126 18 : *searchMode = GIN_SEARCH_MODE_DEFAULT;
127 : else
128 27 : *searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY;
129 45 : 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 977 : PG_RETURN_POINTER(elems);
137 : }
138 :
139 : /*
140 : * consistent support function
141 : */
142 : Datum
143 540 : ginarrayconsistent(PG_FUNCTION_ARGS)
144 : {
145 540 : bool *check = (bool *) PG_GETARG_POINTER(0);
146 540 : StrategyNumber strategy = PG_GETARG_UINT16(1);
147 : #ifdef NOT_USED
148 : ArrayType *query = PG_GETARG_ARRAYTYPE_P(2);
149 : #endif
150 540 : int32 nkeys = PG_GETARG_INT32(3);
151 : #ifdef NOT_USED
152 : Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4);
153 : #endif
154 540 : bool *recheck = (bool *) PG_GETARG_POINTER(5);
155 : #ifdef NOT_USED
156 : Datum *queryKeys = (Datum *) PG_GETARG_POINTER(6);
157 : #endif
158 540 : bool *nullFlags = (bool *) PG_GETARG_POINTER(7);
159 : bool res;
160 : int32 i;
161 :
162 540 : 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 540 : case GinContainsStrategy:
179 : /* result is not lossy */
180 540 : *recheck = false;
181 : /* must have all elements in check[] true, and no nulls */
182 540 : res = true;
183 740 : for (i = 0; i < nkeys; i++)
184 : {
185 200 : if (!check[i] || nullFlags[i])
186 : {
187 0 : res = false;
188 0 : break;
189 : }
190 : }
191 540 : 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 540 : PG_RETURN_BOOL(res);
224 : }
225 :
226 : /*
227 : * triconsistent support function
228 : */
229 : Datum
230 508359 : ginarraytriconsistent(PG_FUNCTION_ARGS)
231 : {
232 508359 : GinTernaryValue *check = (GinTernaryValue *) PG_GETARG_POINTER(0);
233 508359 : StrategyNumber strategy = PG_GETARG_UINT16(1);
234 : #ifdef NOT_USED
235 : ArrayType *query = PG_GETARG_ARRAYTYPE_P(2);
236 : #endif
237 508359 : 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 508359 : bool *nullFlags = (bool *) PG_GETARG_POINTER(6);
243 : GinTernaryValue res;
244 : int32 i;
245 :
246 508359 : switch (strategy)
247 : {
248 1808 : case GinOverlapStrategy:
249 : /* must have a match for at least one non-null element */
250 1808 : res = GIN_FALSE;
251 461140 : for (i = 0; i < nkeys; i++)
252 : {
253 459637 : if (!nullFlags[i])
254 : {
255 459637 : if (check[i] == GIN_TRUE)
256 : {
257 305 : res = GIN_TRUE;
258 305 : break;
259 : }
260 459332 : else if (check[i] == GIN_MAYBE && res == GIN_FALSE)
261 : {
262 1503 : res = GIN_MAYBE;
263 : }
264 : }
265 : }
266 1808 : break;
267 506279 : case GinContainsStrategy:
268 : /* must have all elements in check[] true, and no nulls */
269 506279 : res = GIN_TRUE;
270 931718 : for (i = 0; i < nkeys; i++)
271 : {
272 425471 : if (check[i] == GIN_FALSE || nullFlags[i])
273 : {
274 32 : res = GIN_FALSE;
275 32 : break;
276 : }
277 425439 : if (check[i] == GIN_MAYBE)
278 : {
279 8 : res = GIN_MAYBE;
280 : }
281 : }
282 506279 : break;
283 224 : case GinContainedStrategy:
284 : /* can't do anything else useful here */
285 224 : res = GIN_MAYBE;
286 224 : break;
287 48 : 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 48 : res = GIN_MAYBE;
295 88 : for (i = 0; i < nkeys; i++)
296 : {
297 68 : if (check[i] == GIN_FALSE)
298 : {
299 28 : res = GIN_FALSE;
300 28 : break;
301 : }
302 : }
303 48 : break;
304 0 : default:
305 0 : elog(ERROR, "ginarrayconsistent: unknown strategy number: %d",
306 : strategy);
307 : res = false;
308 : }
309 :
310 508359 : PG_RETURN_GIN_TERNARY_VALUE(res);
311 : }
|