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-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
7102 bruce@momjian.us 33 :CBC 569324 : ginarrayextract(PG_FUNCTION_ARGS)
34 : : {
35 : : /* Make copy of array input to ensure it doesn't disappear while in use */
5546 tgl@sss.pgh.pa.us 36 : 569324 : ArrayType *array = PG_GETARG_ARRAYTYPE_P_COPY(0);
37 : 569324 : int32 *nkeys = (int32 *) PG_GETARG_POINTER(1);
38 : 569324 : 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 : :
7257 teodor@sigaev.ru 46 : 569324 : get_typlenbyvalalign(ARR_ELEMTYPE(array),
47 : : &elmlen, &elmbyval, &elmalign);
48 : :
49 : 569324 : deconstruct_array(array,
50 : : ARR_ELEMTYPE(array),
51 : : elmlen, elmbyval, elmalign,
52 : : &elems, &nulls, &nelems);
53 : :
5546 tgl@sss.pgh.pa.us 54 : 569324 : *nkeys = nelems;
55 : 569324 : *nullFlags = nulls;
56 : :
57 : : /* we should not free array, elems[i] points into it */
58 : 569324 : 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
5506 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
6781 tgl@sss.pgh.pa.us 79 :CBC 666 : ginqueryarrayextract(PG_FUNCTION_ARGS)
80 : : {
81 : : /* Make copy of array input to ensure it doesn't disappear while in use */
5546 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;
5546 tgl@sss.pgh.pa.us 130 :UBC 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 */
5546 tgl@sss.pgh.pa.us 136 :CBC 666 : PG_RETURN_POINTER(elems);
137 : : }
138 : :
139 : : /*
140 : : * consistent support function
141 : : */
142 : : Datum
7102 bruce@momjian.us 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
5546 tgl@sss.pgh.pa.us 150 : 405 : int32 nkeys = PG_GETARG_INT32(3);
151 : : #ifdef NOT_USED
152 : : Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4);
153 : : #endif
6199 154 : 405 : bool *recheck = (bool *) PG_GETARG_POINTER(5);
155 : : #ifdef NOT_USED
156 : : Datum *queryKeys = (Datum *) PG_GETARG_POINTER(6);
157 : : #endif
5546 158 : 405 : bool *nullFlags = (bool *) PG_GETARG_POINTER(7);
159 : : bool res;
160 : : int32 i;
161 : :
7102 bruce@momjian.us 162 [ - + - - : 405 : switch (strategy)
- ]
163 : : {
7257 teodor@sigaev.ru 164 :UBC 0 : case GinOverlapStrategy:
165 : : /* result is not lossy */
6544 tgl@sss.pgh.pa.us 166 : 0 : *recheck = false;
167 : : /* must have a match for at least one non-null element */
5546 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 : : }
7257 teodor@sigaev.ru 177 : 0 : break;
7257 teodor@sigaev.ru 178 :CBC 405 : case GinContainsStrategy:
179 : : /* result is not lossy */
6544 tgl@sss.pgh.pa.us 180 : 405 : *recheck = false;
181 : : /* must have all elements in check[] true, and no nulls */
182 : 405 : res = true;
5546 183 [ + + ]: 555 : for (i = 0; i < nkeys; i++)
184 : : {
185 [ + - - + ]: 150 : if (!check[i] || nullFlags[i])
186 : : {
6544 tgl@sss.pgh.pa.us 187 :UBC 0 : res = false;
188 : 0 : break;
189 : : }
190 : : }
6544 tgl@sss.pgh.pa.us 191 :CBC 405 : break;
5546 tgl@sss.pgh.pa.us 192 :UBC 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;
7187 teodor@sigaev.ru 198 : 0 : case GinEqualStrategy:
199 : : /* we will need recheck */
6544 tgl@sss.pgh.pa.us 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;
5546 208 [ # # ]: 0 : for (i = 0; i < nkeys; i++)
209 : : {
7102 bruce@momjian.us 210 [ # # ]: 0 : if (!check[i])
211 : : {
6544 tgl@sss.pgh.pa.us 212 : 0 : res = false;
7257 teodor@sigaev.ru 213 : 0 : break;
214 : : }
215 : : }
216 : 0 : break;
217 : 0 : default:
7126 tgl@sss.pgh.pa.us 218 [ # # ]: 0 : elog(ERROR, "ginarrayconsistent: unknown strategy number: %d",
219 : : strategy);
220 : : res = false;
221 : : }
222 : :
7257 teodor@sigaev.ru 223 :CBC 405 : PG_RETURN_BOOL(res);
224 : : }
225 : :
226 : : /*
227 : : * triconsistent support function
228 : : */
229 : : Datum
4386 heikki.linnakangas@i 230 : 404362 : ginarraytriconsistent(PG_FUNCTION_ARGS)
231 : : {
4367 232 : 404362 : GinTernaryValue *check = (GinTernaryValue *) PG_GETARG_POINTER(0);
4386 233 : 404362 : StrategyNumber strategy = PG_GETARG_UINT16(1);
234 : : #ifdef NOT_USED
235 : : ArrayType *query = PG_GETARG_ARRAYTYPE_P(2);
236 : : #endif
237 : 404362 : 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 : 404362 : bool *nullFlags = (bool *) PG_GETARG_POINTER(6);
243 : : GinTernaryValue res;
244 : : int32 i;
245 : :
246 [ + + + + : 404362 : 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 : 402412 : case GinContainsStrategy:
268 : : /* must have all elements in check[] true, and no nulls */
269 : 402412 : res = GIN_TRUE;
270 [ + + ]: 744194 : for (i = 0; i < nkeys; i++)
271 : : {
272 [ + + - + ]: 341806 : if (check[i] == GIN_FALSE || nullFlags[i])
273 : : {
274 : 24 : res = GIN_FALSE;
275 : 24 : break;
276 : : }
277 [ + + ]: 341782 : if (check[i] == GIN_MAYBE)
278 : : {
279 : 6 : res = GIN_MAYBE;
280 : : }
281 : : }
282 : 402412 : 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;
4386 heikki.linnakangas@i 304 :UBC 0 : default:
305 [ # # ]: 0 : elog(ERROR, "ginarrayconsistent: unknown strategy number: %d",
306 : : strategy);
307 : : res = false;
308 : : }
309 : :
4367 heikki.linnakangas@i 310 :CBC 404362 : PG_RETURN_GIN_TERNARY_VALUE(res);
311 : : }
|