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